You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ko...@apache.org on 2018/02/20 08:47:27 UTC

[1/7] lucene-solr:master: SOLR-11795: Add Solr metrics exporter for Prometheus

Repository: lucene-solr
Updated Branches:
  refs/heads/master dfc0fe86e -> 4bfcbc5c6


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/config/SolrQueryConfigTest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/config/SolrQueryConfigTest.java b/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/config/SolrQueryConfigTest.java
new file mode 100644
index 0000000..c62d354
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/config/SolrQueryConfigTest.java
@@ -0,0 +1,121 @@
+/*
+ * 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.prometheus.scraper.config;
+
+import org.apache.solr.SolrTestCaseJ4;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.List;
+
+/**
+ * Unit test for SolrQueryConfig.
+ */
+public class SolrQueryConfigTest extends SolrTestCaseJ4 {
+  @Test
+  public void testQueryConfig() throws Exception {
+    SolrQueryConfig queryConfig = new SolrQueryConfig();
+
+    assertNotNull(queryConfig);
+  }
+
+  @Test
+  public void testGetCollection() throws Exception {
+    SolrQueryConfig queryConfig = new SolrQueryConfig();
+
+    String expected = "";
+    String actual = queryConfig.getCollection();
+    assertEquals(expected, actual);
+  }
+
+  @Test
+  public void testSetCollection() throws Exception {
+    SolrQueryConfig queryConfig = new SolrQueryConfig();
+
+    queryConfig.setCollection("collection1");
+
+    String expected = "collection1";
+    String actual = queryConfig.getCollection();
+    assertEquals(expected, actual);
+  }
+
+  @Test
+  public void testGetPath() throws Exception {
+    SolrQueryConfig queryConfig = new SolrQueryConfig();
+
+    String expected = "";
+    String actual = queryConfig.getPath();
+    assertEquals(expected, actual);
+  }
+
+  @Test
+  public void testSetPath() throws Exception {
+    SolrQueryConfig queryConfig = new SolrQueryConfig();
+
+    queryConfig.setPath("/select");
+
+    String expected = "/select";
+    String actual = queryConfig.getPath();
+    assertEquals(expected, actual);
+  }
+
+  @Test
+  public void testGetParams() throws Exception {
+    SolrQueryConfig queryConfig = new SolrQueryConfig();
+
+    List<LinkedHashMap<String, String>> expected = new ArrayList<>();
+    List<LinkedHashMap<String, String>> actual = queryConfig.getParams();
+    assertEquals(expected, actual);
+  }
+
+  @Test
+  public void testSetParams() throws Exception {
+    SolrQueryConfig queryConfig = new SolrQueryConfig();
+
+    LinkedHashMap<String,String> param1 = new LinkedHashMap<>();
+    param1.put("q", "*:*");
+
+    LinkedHashMap<String,String> param2 = new LinkedHashMap<>();
+    param2.put("facet", "on");
+
+    queryConfig.setParams(Arrays.asList(param1, param2));
+
+    List<LinkedHashMap<String, String>> expected = Arrays.asList(param1, param2);
+    List<LinkedHashMap<String, String>> actual = queryConfig.getParams();
+    assertEquals(expected, actual);
+  }
+
+  @Test
+  public void testGetParamsString() throws Exception {
+    SolrQueryConfig queryConfig = new SolrQueryConfig();
+
+    LinkedHashMap<String,String> param1 = new LinkedHashMap<>();
+    param1.put("q", "*:*");
+    param1.put("fq", "manu:apple");
+
+    LinkedHashMap<String,String> param2 = new LinkedHashMap<>();
+    param2.put("facet", "on");
+
+    queryConfig.setParams(Arrays.asList(param1, param2));
+
+    String expected = "q=*:*&fq=manu:apple&facet=on";
+    String actual = queryConfig.getParamsString();
+    assertEquals(expected, actual);
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/config/SolrScraperConfigTest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/config/SolrScraperConfigTest.java b/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/config/SolrScraperConfigTest.java
new file mode 100644
index 0000000..79d1204
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/config/SolrScraperConfigTest.java
@@ -0,0 +1,86 @@
+/*
+ * 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.prometheus.scraper.config;
+
+import org.apache.solr.prometheus.collector.config.SolrCollectorConfig;
+import org.apache.solr.SolrTestCaseJ4;
+import org.junit.Test;
+import org.yaml.snakeyaml.Yaml;
+
+import java.io.FileReader;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Unit test for SolrScraperConfig.
+ */
+public class SolrScraperConfigTest extends SolrTestCaseJ4 {
+  @Test
+  public void testScraperConfig() throws Exception {
+    String configFile = getFile("conf/config.yml").getAbsolutePath();
+
+    SolrCollectorConfig config = new Yaml().loadAs(new FileReader(configFile), SolrCollectorConfig.class);
+
+    SolrScraperConfig scraperConfig = config.getMetrics();
+
+    assertNotNull(scraperConfig);
+  }
+
+  @Test
+  public void testGetJsonQueries() throws Exception {
+    String configFile = getFile("conf/config.yml").getAbsolutePath();
+
+    SolrCollectorConfig collectorConfig = new Yaml().loadAs(new FileReader(configFile), SolrCollectorConfig.class);
+
+    SolrScraperConfig scraperConfig = collectorConfig.getMetrics();
+
+    assertNotNull(scraperConfig.getJsonQueries());
+  }
+
+  @Test
+  public void testSetJsonQueries() throws Exception {
+    List<String> jsonQueries = new ArrayList<>();
+
+    SolrScraperConfig scraperConfig = new SolrScraperConfig();
+
+    scraperConfig.setJsonQueries(jsonQueries);
+
+    assertNotNull(scraperConfig.getJsonQueries());
+  }
+
+  @Test
+  public void testGetQueryConfig() throws Exception {
+    String configFile = getFile("conf/config.yml").getAbsolutePath();
+
+    SolrCollectorConfig collectorConfig = new Yaml().loadAs(new FileReader(configFile), SolrCollectorConfig.class);
+
+    SolrScraperConfig scraperConfig = collectorConfig.getMetrics();
+
+    assertNotNull(scraperConfig.getQuery());
+  }
+
+  @Test
+  public void testSetQueryConfig() throws Exception {
+    SolrQueryConfig queryConfig = new SolrQueryConfig();
+
+    SolrScraperConfig scraperConfig = new SolrScraperConfig();
+
+    scraperConfig.setQuery(queryConfig);
+
+    assertNotNull(scraperConfig.getQuery());
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/solr-ref-guide/src/images/monitoring-solr-with-prometheus-and-grafana/grafana-solr-dashboard.png
----------------------------------------------------------------------
diff --git a/solr/solr-ref-guide/src/images/monitoring-solr-with-prometheus-and-grafana/grafana-solr-dashboard.png b/solr/solr-ref-guide/src/images/monitoring-solr-with-prometheus-and-grafana/grafana-solr-dashboard.png
new file mode 100644
index 0000000..69f21a4
Binary files /dev/null and b/solr/solr-ref-guide/src/images/monitoring-solr-with-prometheus-and-grafana/grafana-solr-dashboard.png differ

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/solr-ref-guide/src/images/monitoring-solr-with-prometheus-and-grafana/solr-exporter-diagram.png
----------------------------------------------------------------------
diff --git a/solr/solr-ref-guide/src/images/monitoring-solr-with-prometheus-and-grafana/solr-exporter-diagram.png b/solr/solr-ref-guide/src/images/monitoring-solr-with-prometheus-and-grafana/solr-exporter-diagram.png
new file mode 100644
index 0000000..96efece
Binary files /dev/null and b/solr/solr-ref-guide/src/images/monitoring-solr-with-prometheus-and-grafana/solr-exporter-diagram.png differ

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/solr-ref-guide/src/monitoring-solr-with-prometheus-and-grafana.adoc
----------------------------------------------------------------------
diff --git a/solr/solr-ref-guide/src/monitoring-solr-with-prometheus-and-grafana.adoc b/solr/solr-ref-guide/src/monitoring-solr-with-prometheus-and-grafana.adoc
new file mode 100644
index 0000000..1ac55a2
--- /dev/null
+++ b/solr/solr-ref-guide/src/monitoring-solr-with-prometheus-and-grafana.adoc
@@ -0,0 +1,250 @@
+= Monitoring Solr with Prometheus and Grafana
+// 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.
+
+You can monitor Solr using solr-exporter that exposes Solr's metrics to https://prometheus.io[Prometheus], and visualize metrics using https://grafana.com[Grafana].
+
+It allows users to monitor not only Solr metrics which come from <<metrics-reporting.adoc#metrics-api,Metrics API>> but also facet counts which come from <<searching.adoc#searching,Searching>>.
+
+.solr-exporter Diagram
+image::images/monitoring-solr-with-prometheus-and-grafana/solr-exporter-diagram.png[image,width=600]
+
+This feature is experimental status.
+
+== Running solr-exporter
+
+You can start solr-exporter by running `./bin/solr-exporter` from the solr-exporter directory.
+
+[source,plain]
+----
+$ cd ./contrib/prometheus-exporter
+$ ./bin/solr-exporter -p 9983 -b http://localhost:8983/solr -f ./conf/config.yml -n 8
+----
+
+If you are on Windows platform, you can start solr-exporter by running `.\bin\solr-exporter.cmd` instead.
+
+[source,plain]
+----
+> cd .\contrib\prometheus
+> .\bin\solr-exporter.cmd -p 9983 -b http://localhost:8983/solr -f .\conf\config.yml -n 8
+----
+
+You can also connect to Solr in SolrCloud mode like this.
+
+[source,plain]
+----
+$ cd ./contrib/prometheus
+$ ./bin/solr-exporter -p 9983 -z localhost:2181/solr -f ./conf/config.yml -n 16
+----
+
+See command help:
+
+[source,plain]
+----
+$ ./bin/solr-exporter -h
+usage: SolrCollector [-h] [-v] [-p PORT] [-b BASE_URL] [-z ZK_HOST] [-f CONFIG]
+                     [-n NUM_THREADS]
+
+Prometheus exporter for Apache Solr.
+
+optional arguments:
+  -h, --help             show this help message and exit
+  -p PORT, --port PORT   solr-exporter listen port
+  -b BASE_URL, --baseurl BASE_URL
+                         specify Solr base URL when connecting  to Solr in standalone mode (for
+                         example 'http://localhost:8983/solr')
+  -z ZK_HOST, --zkhost ZK_HOST
+                         specify  ZooKeeper  connection  string  when  connecting  to  Solr  in
+                         SolrCloud mode (for example 'localhost:2181/solr')
+  -f CONFIG, --config-file CONFIG
+                         specify configuration file
+  -n NUM_THREADS, --num-thread NUM_THREADS
+                         specify number of threads
+----
+
+The Solr's metrics exposed by solr-exporter can see at the following URL.
+
+http://localhost:9983/metrics[http://localhost:9983/metrics]
+
+
+== Configuration
+
+The configuration is in `./config/config.yml`. An example with all possible options:
+
+[source,plain]
+----
+ping:
+  query:
+    path: /admin/ping
+  jsonQueries:
+    - |-
+      . as $object | $object |
+      (if $object.status == "OK" then 1.0 else 0.0 end) as $value |
+      {
+        name         : "solr_ping",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/ping.html",
+        label_names  : [],
+        label_values : [],
+        value        : $value
+      }
+
+metrics:
+  query:
+    path: /admin/metrics
+    params:
+      - group: 'all'
+      - type: 'all'
+      - prefix: ''
+      - property: ''
+  jsonQueries:
+    # solr_metrics_jetty_response_count
+    - |-
+      .metrics["solr.jetty"] | to_entries | .[] | select(.key | startswith("org.eclipse.jetty.server.handler.DefaultHandler")) | select(.key | endswith("xx-responses")) as $object |
+      $object.key | split(".") | last | split("-") | first as $status |
+      $object.value.count as $value |
+      {
+        name         : "solr_metrics_jetty_response_count",
+        type         : "gauge",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["status"],
+        label_values : [$status],
+        value        : $value
+      }
+
+...
+
+collections:
+  query:
+    path: /admin/collections
+    params:
+      - action: 'CLUSTERSTATUS'
+  jsonQueries:
+    # solr_collections_cluster_status_live_nodes
+    - |-
+      .cluster.live_nodes | length as $value|
+      {
+        name         : "solr_collections_cluster_status_live_nodes",
+        type         : "gauge",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/collections-api.html#clusterstatus",
+        label_names  : [],
+        label_values : [],
+        value        : $value
+      }
+
+...
+
+queries:
+  - query:
+      collection: collection1
+      path: /select
+      params:
+        - q: "*:*"
+        - start: 0
+        - rows: 0
+        - json.facet: |-
+            {
+              category: {
+                type: terms,
+                field: cat
+              }
+            }
+    jsonQueries:
+      # solr_facets_category
+      - |-
+        .facets.category.buckets[] as $object |
+        $object.val as $term |
+        $object.count as $value |
+        {
+          name         : "solr_facets_category",
+          type         : "gauge",
+          help         : "Category facets",
+          label_names  : ["term"],
+          label_values : [$term],
+          value        : $value
+        }
+----
+
+|===
+|Name|Description
+
+|ping|Scrape <<ping.adoc#ping,Ping>> response.
+|metrics|Scrape <<metrics-reporting.adoc#metrics-api,Metrics API>> response.
+|collections|Scrape <<collections-api.adoc#collections-api,Collections API>> response.
+|queries|Scrape <<searching.adoc#searching,Search API>> response.
+|*.query|Query parameter for each features. You can specify `collection`, `core`, `path`, and `params`.
+|*.jsonQueries|JSON Query that is jq syntax. For more details, see https://stedolan.github.io/jq/manual/[https://stedolan.github.io/jq/manual/].
+|===
+
+jq query has to output JSON in the following format.
+
+[source,json]
+----
+{
+  name         : "solr_ping",
+  type         : "GAUGE",
+  help         : "See following URL: https://lucene.apache.org/solr/guide/ping.html",
+  label_names  : ["base_url","core"],
+  label_values : ["http://localhost:8983/solr","collection1"],
+  value        : 1.0
+}
+----
+
+It will be converted to the following exposition format.
+
+[source,plain]
+----
+# TYPE solr_ping gauge
+# HELP solr_ping See following URL: https://lucene.apache.org/solr/guide/ping.html
+solr_ping{base_url="http://localhost:8983/solr",core="collection1"} 1.0
+----
+
+|===
+|Name|Description
+
+|name|The metric name to set. For more details, see https://prometheus.io/docs/practices/naming/[https://prometheus.io/docs/practices/naming/].
+|type|The type of the metric, can be `COUNTER`, `GAUGE`, `SUMMARY`, `HISTOGRAM` or `UNTYPED`. For more detauils, see https://prometheus.io/docs/concepts/metric_types/[https://prometheus.io/docs/concepts/metric_types/].
+|help|Help text for the metric.
+|label_names|Label names for the metric. For more details, see https://prometheus.io/docs/practices/naming/[https://prometheus.io/docs/practices/naming/].
+|label_values|Label values for the metric. For more details, see https://prometheus.io/docs/practices/naming/[https://prometheus.io/docs/practices/naming/].
+|value|Value for the metric. Value must be set to Double type.
+|===
+
+
+== Prometheus Settings
+
+You need to specify the solr-exporter listen address into `scrape_configs` in `prometheus.yml`. See following example:
+
+[source,plain]
+----
+scrape_configs:
+  - job_name: 'solr'
+    static_configs:
+      - targets: ['localhost:9983']
+----
+
+When you apply the above settings to prometheus, it will start to pull Solr's metrics from solr-exporter.
+
+
+== Grafana Dashboard
+
+A Grafana sample dashboard is provided at the following JSON file.
+
+`./conf/grafana-solr-dashboard.json`
+
+.Grafana Dashboard
+image::images/monitoring-solr-with-prometheus-and-grafana/grafana-solr-dashboard.png[image,width=800]

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/solr-ref-guide/src/monitoring-solr.adoc
----------------------------------------------------------------------
diff --git a/solr/solr-ref-guide/src/monitoring-solr.adoc b/solr/solr-ref-guide/src/monitoring-solr.adoc
index 0576e53..2fb7077 100644
--- a/solr/solr-ref-guide/src/monitoring-solr.adoc
+++ b/solr/solr-ref-guide/src/monitoring-solr.adoc
@@ -1,5 +1,5 @@
 = Monitoring Solr
-:page-children: metrics-reporting, mbean-request-handler, configuring-logging, using-jmx-with-solr, performance-statistics-reference
+:page-children: metrics-reporting, mbean-request-handler, configuring-logging, using-jmx-with-solr, monitoring-solr-with-prometheus-and-grafana, performance-statistics-reference
 // 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
@@ -30,6 +30,8 @@ Common administrative tasks include:
 
 <<using-jmx-with-solr.adoc#using-jmx-with-solr,Using JMX with Solr>>: Describes how to use Java Management Extensions with Solr.
 
+<<monitoring-solr-with-prometheus-and-grafana.adoc#monitoring-solr-with-prometheus-and-grafana,Monitoring Solr with Prometheus and Grafana>>: Describes how to monitor Solr with Prometheus and Grafana.
+
 <<performance-statistics-reference.adoc#performance-statistics-reference,Performance Statistics Reference>>: Additional information on statistics returned from JMX.
 
 


[5/7] lucene-solr:master: SOLR-11795: Add Solr metrics exporter for Prometheus

Posted by ko...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/conf/grafana-solr-dashboard.json
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/conf/grafana-solr-dashboard.json b/solr/contrib/prometheus-exporter/conf/grafana-solr-dashboard.json
new file mode 100644
index 0000000..96fb818
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/conf/grafana-solr-dashboard.json
@@ -0,0 +1,4465 @@
+{
+  "__inputs": [
+    {
+      "name": "DS_PROMETHEUS",
+      "label": "Prometheus",
+      "description": "",
+      "type": "datasource",
+      "pluginId": "prometheus",
+      "pluginName": "Prometheus"
+    }
+  ],
+  "__requires": [
+    {
+      "type": "grafana",
+      "id": "grafana",
+      "name": "Grafana",
+      "version": "4.6.3"
+    },
+    {
+      "type": "panel",
+      "id": "graph",
+      "name": "Graph",
+      "version": ""
+    },
+    {
+      "type": "datasource",
+      "id": "prometheus",
+      "name": "Prometheus",
+      "version": "1.0.0"
+    }
+  ],
+  "annotations": {
+    "list": [
+      {
+        "builtIn": 1,
+        "datasource": "-- Grafana --",
+        "enable": true,
+        "hide": true,
+        "iconColor": "rgba(0, 211, 255, 1)",
+        "name": "Annotations & Alerts",
+        "type": "dashboard"
+      }
+    ]
+  },
+  "description": "Solr Dashboard",
+  "editable": true,
+  "gnetId": null,
+  "graphTooltip": 0,
+  "hideControls": false,
+  "id": null,
+  "links": [],
+  "refresh": "1m",
+  "rows": [
+    {
+      "collapse": false,
+      "height": "250px",
+      "panels": [
+        {
+          "aliasColors": {},
+          "bars": false,
+          "dashLength": 10,
+          "dashes": false,
+          "datasource": "${DS_PROMETHEUS}",
+          "fill": 1,
+          "id": 2,
+          "legend": {
+            "alignAsTable": true,
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "null",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "spaceLength": 10,
+          "span": 6,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "expr": "increase(solr_metrics_jetty_requests_total{base_url=~\"$base_url\"}[1m])",
+              "format": "time_series",
+              "intervalFactor": 2,
+              "legendFormat": "{{base_url}} {{method}}",
+              "refId": "A"
+            }
+          ],
+          "thresholds": [],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "Requests",
+          "tooltip": {
+            "shared": true,
+            "sort": 0,
+            "value_type": "individual"
+          },
+          "type": "graph",
+          "xaxis": {
+            "buckets": null,
+            "mode": "time",
+            "name": null,
+            "show": true,
+            "values": []
+          },
+          "yaxes": [
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": "0",
+              "show": true
+            },
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        },
+        {
+          "aliasColors": {},
+          "bars": false,
+          "dashLength": 10,
+          "dashes": false,
+          "datasource": "${DS_PROMETHEUS}",
+          "description": "",
+          "fill": 1,
+          "id": 1,
+          "legend": {
+            "alignAsTable": true,
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "null",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "spaceLength": 10,
+          "span": 6,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "expr": "increase(solr_metrics_jetty_response_total{base_url=~\"$base_url\"}[1m])",
+              "format": "time_series",
+              "intervalFactor": 2,
+              "legendFormat": "{{base_url}} {{status}}",
+              "refId": "A",
+              "step": 40
+            }
+          ],
+          "thresholds": [],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "Response",
+          "tooltip": {
+            "shared": true,
+            "sort": 0,
+            "value_type": "individual"
+          },
+          "type": "graph",
+          "xaxis": {
+            "buckets": null,
+            "mode": "time",
+            "name": null,
+            "show": true,
+            "values": []
+          },
+          "yaxes": [
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": "0",
+              "show": true
+            },
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        },
+        {
+          "aliasColors": {},
+          "bars": false,
+          "dashLength": 10,
+          "dashes": false,
+          "datasource": "${DS_PROMETHEUS}",
+          "fill": 1,
+          "id": 55,
+          "legend": {
+            "alignAsTable": true,
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "rightSide": true,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "null",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "spaceLength": 10,
+          "span": 12,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "expr": "increase(solr_metrics_jetty_dispatches_total{base_url=~\"$base_url\"}[1m])",
+              "format": "time_series",
+              "intervalFactor": 2,
+              "legendFormat": "{{base_url}}",
+              "refId": "A"
+            }
+          ],
+          "thresholds": [],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "Dispatches",
+          "tooltip": {
+            "shared": true,
+            "sort": 0,
+            "value_type": "individual"
+          },
+          "type": "graph",
+          "xaxis": {
+            "buckets": null,
+            "mode": "time",
+            "name": null,
+            "show": true,
+            "values": []
+          },
+          "yaxes": [
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": "0",
+              "show": true
+            },
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        }
+      ],
+      "repeat": null,
+      "repeatIteration": null,
+      "repeatRowId": null,
+      "showTitle": true,
+      "title": "Jetty Metrics",
+      "titleSize": "h3"
+    },
+    {
+      "collapse": false,
+      "height": 250,
+      "panels": [
+        {
+          "aliasColors": {},
+          "bars": false,
+          "dashLength": 10,
+          "dashes": false,
+          "datasource": "${DS_PROMETHEUS}",
+          "fill": 1,
+          "id": 3,
+          "legend": {
+            "alignAsTable": true,
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "null",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "spaceLength": 10,
+          "span": 6,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "expr": "solr_metrics_jvm_buffers{base_url=~\"$base_url\"}",
+              "format": "time_series",
+              "intervalFactor": 2,
+              "legendFormat": "{{base_url}} {{pool}}",
+              "refId": "A"
+            }
+          ],
+          "thresholds": [],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "Buffers",
+          "tooltip": {
+            "shared": true,
+            "sort": 0,
+            "value_type": "individual"
+          },
+          "type": "graph",
+          "xaxis": {
+            "buckets": null,
+            "mode": "time",
+            "name": null,
+            "show": true,
+            "values": []
+          },
+          "yaxes": [
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": "0",
+              "show": true
+            },
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        },
+        {
+          "aliasColors": {},
+          "bars": false,
+          "dashLength": 10,
+          "dashes": false,
+          "datasource": "${DS_PROMETHEUS}",
+          "fill": 1,
+          "id": 4,
+          "legend": {
+            "alignAsTable": true,
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "null",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "spaceLength": 10,
+          "span": 6,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "expr": "solr_metrics_jvm_buffers_bytes{base_url=~\"$base_url\"}",
+              "format": "time_series",
+              "intervalFactor": 2,
+              "legendFormat": "{{base_url}} {{pool}} {{item}}",
+              "refId": "A"
+            }
+          ],
+          "thresholds": [],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "Buffer Size",
+          "tooltip": {
+            "shared": true,
+            "sort": 0,
+            "value_type": "individual"
+          },
+          "type": "graph",
+          "xaxis": {
+            "buckets": null,
+            "mode": "time",
+            "name": null,
+            "show": true,
+            "values": []
+          },
+          "yaxes": [
+            {
+              "format": "decbytes",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": "0",
+              "show": true
+            },
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        },
+        {
+          "aliasColors": {},
+          "bars": false,
+          "dashLength": 10,
+          "dashes": false,
+          "datasource": "${DS_PROMETHEUS}",
+          "fill": 1,
+          "id": 5,
+          "legend": {
+            "alignAsTable": true,
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "null",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "spaceLength": 10,
+          "span": 6,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "expr": "increase(solr_metrics_jvm_gc_total{base_url=~\"$base_url\"}[1m])",
+              "format": "time_series",
+              "intervalFactor": 2,
+              "legendFormat": "{{base_url}} {{item}}",
+              "refId": "A"
+            }
+          ],
+          "thresholds": [],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "GC Count",
+          "tooltip": {
+            "shared": true,
+            "sort": 0,
+            "value_type": "individual"
+          },
+          "type": "graph",
+          "xaxis": {
+            "buckets": null,
+            "mode": "time",
+            "name": null,
+            "show": true,
+            "values": []
+          },
+          "yaxes": [
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": "0",
+              "show": true
+            },
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        },
+        {
+          "aliasColors": {},
+          "bars": false,
+          "dashLength": 10,
+          "dashes": false,
+          "datasource": "${DS_PROMETHEUS}",
+          "fill": 1,
+          "id": 6,
+          "legend": {
+            "alignAsTable": true,
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "null",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "spaceLength": 10,
+          "span": 6,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "expr": "increase(solr_metrics_jvm_gc_seconds_total{base_url=~\"$base_url\"}[1m])",
+              "format": "time_series",
+              "intervalFactor": 2,
+              "legendFormat": "{{base_url}} {{item}}",
+              "refId": "A"
+            }
+          ],
+          "thresholds": [],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "GC Time",
+          "tooltip": {
+            "shared": true,
+            "sort": 0,
+            "value_type": "individual"
+          },
+          "type": "graph",
+          "xaxis": {
+            "buckets": null,
+            "mode": "time",
+            "name": null,
+            "show": true,
+            "values": []
+          },
+          "yaxes": [
+            {
+              "decimals": null,
+              "format": "s",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": "0",
+              "show": true
+            },
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        },
+        {
+          "aliasColors": {},
+          "bars": false,
+          "dashLength": 10,
+          "dashes": false,
+          "datasource": "${DS_PROMETHEUS}",
+          "fill": 1,
+          "id": 7,
+          "legend": {
+            "alignAsTable": true,
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "null",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "spaceLength": 10,
+          "span": 6,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "expr": "solr_metrics_jvm_memory_heap_bytes{base_url=~\"$base_url\"}",
+              "format": "time_series",
+              "intervalFactor": 2,
+              "legendFormat": "{{base_url}} {{item}}",
+              "refId": "A"
+            }
+          ],
+          "thresholds": [],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "Heap Size",
+          "tooltip": {
+            "shared": true,
+            "sort": 0,
+            "value_type": "individual"
+          },
+          "type": "graph",
+          "xaxis": {
+            "buckets": null,
+            "mode": "time",
+            "name": null,
+            "show": true,
+            "values": []
+          },
+          "yaxes": [
+            {
+              "format": "decbytes",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": "0",
+              "show": true
+            },
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        },
+        {
+          "aliasColors": {},
+          "bars": false,
+          "dashLength": 10,
+          "dashes": false,
+          "datasource": "${DS_PROMETHEUS}",
+          "fill": 1,
+          "id": 8,
+          "legend": {
+            "alignAsTable": true,
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "null",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "spaceLength": 10,
+          "span": 6,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "expr": "solr_metrics_jvm_memory_non_heap_bytes{base_url=~\"$base_url\"}",
+              "format": "time_series",
+              "intervalFactor": 2,
+              "legendFormat": "{{base_url}} {{item}}",
+              "refId": "A"
+            }
+          ],
+          "thresholds": [],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "Non-Heap Size",
+          "tooltip": {
+            "shared": true,
+            "sort": 0,
+            "value_type": "individual"
+          },
+          "type": "graph",
+          "xaxis": {
+            "buckets": null,
+            "mode": "time",
+            "name": null,
+            "show": true,
+            "values": []
+          },
+          "yaxes": [
+            {
+              "format": "decbytes",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": "0",
+              "show": true
+            },
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        },
+        {
+          "aliasColors": {},
+          "bars": false,
+          "dashLength": 10,
+          "dashes": false,
+          "datasource": "${DS_PROMETHEUS}",
+          "fill": 1,
+          "id": 9,
+          "legend": {
+            "alignAsTable": true,
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "null",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "spaceLength": 10,
+          "span": 6,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "expr": "solr_metrics_jvm_memory_pools_bytes{base_url=~\"$base_url\"}",
+              "format": "time_series",
+              "intervalFactor": 2,
+              "legendFormat": "{{base_url}} {{space}} {{item}}",
+              "refId": "A"
+            }
+          ],
+          "thresholds": [],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "Pool Size",
+          "tooltip": {
+            "shared": true,
+            "sort": 0,
+            "value_type": "individual"
+          },
+          "type": "graph",
+          "xaxis": {
+            "buckets": null,
+            "mode": "time",
+            "name": null,
+            "show": true,
+            "values": []
+          },
+          "yaxes": [
+            {
+              "format": "decbytes",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": "0",
+              "show": true
+            },
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        },
+        {
+          "aliasColors": {},
+          "bars": false,
+          "dashLength": 10,
+          "dashes": false,
+          "datasource": "${DS_PROMETHEUS}",
+          "fill": 1,
+          "id": 10,
+          "legend": {
+            "alignAsTable": true,
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "null",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "spaceLength": 10,
+          "span": 6,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "expr": "solr_metrics_jvm_memory_bytes{base_url=~\"$base_url\"}",
+              "format": "time_series",
+              "intervalFactor": 2,
+              "legendFormat": "{{base_url}} {{item}}",
+              "refId": "A"
+            }
+          ],
+          "thresholds": [],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "Memory Size",
+          "tooltip": {
+            "shared": true,
+            "sort": 0,
+            "value_type": "individual"
+          },
+          "type": "graph",
+          "xaxis": {
+            "buckets": null,
+            "mode": "time",
+            "name": null,
+            "show": true,
+            "values": []
+          },
+          "yaxes": [
+            {
+              "format": "decbytes",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": "0",
+              "show": true
+            },
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        },
+        {
+          "aliasColors": {},
+          "bars": false,
+          "dashLength": 10,
+          "dashes": false,
+          "datasource": "${DS_PROMETHEUS}",
+          "fill": 1,
+          "id": 16,
+          "legend": {
+            "alignAsTable": true,
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "rightSide": true,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "null",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "spaceLength": 10,
+          "span": 12,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "expr": "solr_metrics_jvm_threads{base_url=~\"$base_url\"}",
+              "format": "time_series",
+              "intervalFactor": 2,
+              "legendFormat": "{{base_url}} {{item}}",
+              "refId": "A"
+            }
+          ],
+          "thresholds": [],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "Threads",
+          "tooltip": {
+            "shared": true,
+            "sort": 0,
+            "value_type": "individual"
+          },
+          "type": "graph",
+          "xaxis": {
+            "buckets": null,
+            "mode": "time",
+            "name": null,
+            "show": true,
+            "values": []
+          },
+          "yaxes": [
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": "0",
+              "show": true
+            },
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        }
+      ],
+      "repeat": null,
+      "repeatIteration": null,
+      "repeatRowId": null,
+      "showTitle": true,
+      "title": "JVM Metrics",
+      "titleSize": "h3"
+    },
+    {
+      "collapse": false,
+      "height": 250,
+      "panels": [
+        {
+          "aliasColors": {},
+          "bars": false,
+          "dashLength": 10,
+          "dashes": false,
+          "datasource": "${DS_PROMETHEUS}",
+          "fill": 1,
+          "id": 11,
+          "legend": {
+            "alignAsTable": true,
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "null",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "spaceLength": 10,
+          "span": 6,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "expr": "solr_metrics_jvm_os_memory_bytes{base_url=~\"$base_url\"}",
+              "format": "time_series",
+              "intervalFactor": 2,
+              "legendFormat": "{{base_url}} {{item}}",
+              "refId": "A"
+            }
+          ],
+          "thresholds": [],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "Memory Size",
+          "tooltip": {
+            "shared": true,
+            "sort": 0,
+            "value_type": "individual"
+          },
+          "type": "graph",
+          "xaxis": {
+            "buckets": null,
+            "mode": "time",
+            "name": null,
+            "show": true,
+            "values": []
+          },
+          "yaxes": [
+            {
+              "format": "decbytes",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": "0",
+              "show": true
+            },
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        },
+        {
+          "aliasColors": {},
+          "bars": false,
+          "dashLength": 10,
+          "dashes": false,
+          "datasource": "${DS_PROMETHEUS}",
+          "fill": 1,
+          "id": 12,
+          "legend": {
+            "alignAsTable": true,
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "null",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "spaceLength": 10,
+          "span": 6,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "expr": "solr_metrics_jvm_os_file_descriptors{base_url=~\"$base_url\"}",
+              "format": "time_series",
+              "intervalFactor": 2,
+              "legendFormat": "{{base_url}} {{item}}",
+              "refId": "A"
+            }
+          ],
+          "thresholds": [],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "File Descriptors",
+          "tooltip": {
+            "shared": true,
+            "sort": 0,
+            "value_type": "individual"
+          },
+          "type": "graph",
+          "xaxis": {
+            "buckets": null,
+            "mode": "time",
+            "name": null,
+            "show": true,
+            "values": []
+          },
+          "yaxes": [
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            },
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        },
+        {
+          "aliasColors": {},
+          "bars": false,
+          "dashLength": 10,
+          "dashes": false,
+          "datasource": "${DS_PROMETHEUS}",
+          "fill": 1,
+          "id": 13,
+          "legend": {
+            "alignAsTable": true,
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "null",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "spaceLength": 10,
+          "span": 6,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "expr": "solr_metrics_jvm_os_cpu_load{base_url=~\"$base_url\"}",
+              "format": "time_series",
+              "intervalFactor": 2,
+              "legendFormat": "{{base_url}} {{item}}",
+              "refId": "A"
+            }
+          ],
+          "thresholds": [],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "CPU Load",
+          "tooltip": {
+            "shared": true,
+            "sort": 0,
+            "value_type": "individual"
+          },
+          "type": "graph",
+          "xaxis": {
+            "buckets": null,
+            "mode": "time",
+            "name": null,
+            "show": true,
+            "values": []
+          },
+          "yaxes": [
+            {
+              "format": "percentunit",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": "0",
+              "show": true
+            },
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        },
+        {
+          "aliasColors": {},
+          "bars": false,
+          "dashLength": 10,
+          "dashes": false,
+          "datasource": "${DS_PROMETHEUS}",
+          "fill": 1,
+          "id": 14,
+          "legend": {
+            "alignAsTable": true,
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "null",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "spaceLength": 10,
+          "span": 6,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "expr": "increase(solr_metrics_jvm_os_cpu_time_seconds{base_url=~\"$base_url\"}[1m])",
+              "format": "time_series",
+              "intervalFactor": 2,
+              "legendFormat": "{{base_url}} {{item}}",
+              "refId": "A"
+            }
+          ],
+          "thresholds": [],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "CPU Time",
+          "tooltip": {
+            "shared": true,
+            "sort": 0,
+            "value_type": "individual"
+          },
+          "type": "graph",
+          "xaxis": {
+            "buckets": null,
+            "mode": "time",
+            "name": null,
+            "show": true,
+            "values": []
+          },
+          "yaxes": [
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": "0",
+              "show": true
+            },
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        },
+        {
+          "aliasColors": {},
+          "bars": false,
+          "dashLength": 10,
+          "dashes": false,
+          "datasource": "${DS_PROMETHEUS}",
+          "fill": 1,
+          "id": 15,
+          "legend": {
+            "alignAsTable": true,
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "rightSide": true,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "null",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "spaceLength": 10,
+          "span": 12,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "expr": "solr_metrics_jvm_os_load_average{base_url=~\"$base_url\"}",
+              "format": "time_series",
+              "intervalFactor": 2,
+              "legendFormat": "{{base_url}} {{item}}",
+              "refId": "A"
+            }
+          ],
+          "thresholds": [],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "Load Average",
+          "tooltip": {
+            "shared": true,
+            "sort": 0,
+            "value_type": "individual"
+          },
+          "type": "graph",
+          "xaxis": {
+            "buckets": null,
+            "mode": "time",
+            "name": null,
+            "show": true,
+            "values": []
+          },
+          "yaxes": [
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": "0",
+              "show": true
+            },
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        }
+      ],
+      "repeat": null,
+      "repeatIteration": null,
+      "repeatRowId": null,
+      "showTitle": true,
+      "title": "OS Metrics",
+      "titleSize": "h3"
+    },
+    {
+      "collapse": false,
+      "height": 250,
+      "panels": [
+        {
+          "aliasColors": {},
+          "bars": false,
+          "dashLength": 10,
+          "dashes": false,
+          "datasource": "${DS_PROMETHEUS}",
+          "fill": 1,
+          "id": 19,
+          "legend": {
+            "alignAsTable": true,
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "null",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "spaceLength": 10,
+          "span": 6,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "expr": "increase(solr_metrics_node_requests_total{base_url=~\"$base_url\"}[1m])",
+              "format": "time_series",
+              "intervalFactor": 2,
+              "legendFormat": "{{base_url}}{{handler}}",
+              "refId": "A"
+            }
+          ],
+          "thresholds": [],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "Requests",
+          "tooltip": {
+            "shared": true,
+            "sort": 0,
+            "value_type": "individual"
+          },
+          "type": "graph",
+          "xaxis": {
+            "buckets": null,
+            "mode": "time",
+            "name": null,
+            "show": true,
+            "values": []
+          },
+          "yaxes": [
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": "0",
+              "show": true
+            },
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        },
+        {
+          "aliasColors": {},
+          "bars": false,
+          "dashLength": 10,
+          "dashes": false,
+          "datasource": "${DS_PROMETHEUS}",
+          "fill": 1,
+          "id": 22,
+          "legend": {
+            "alignAsTable": true,
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "null",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "spaceLength": 10,
+          "span": 6,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "expr": "increase(solr_metrics_node_time_seconds_total{base_url=~\"$base_url\"}[1m])",
+              "format": "time_series",
+              "intervalFactor": 2,
+              "legendFormat": "{{base_url}}{{handler}}",
+              "refId": "A"
+            }
+          ],
+          "thresholds": [],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "Request Time",
+          "tooltip": {
+            "shared": true,
+            "sort": 0,
+            "value_type": "individual"
+          },
+          "type": "graph",
+          "xaxis": {
+            "buckets": null,
+            "mode": "time",
+            "name": null,
+            "show": true,
+            "values": []
+          },
+          "yaxes": [
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": "0",
+              "show": true
+            },
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        },
+        {
+          "aliasColors": {},
+          "bars": false,
+          "dashLength": 10,
+          "dashes": false,
+          "datasource": "${DS_PROMETHEUS}",
+          "fill": 1,
+          "id": 17,
+          "legend": {
+            "alignAsTable": true,
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "null",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "spaceLength": 10,
+          "span": 6,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "expr": "increase(solr_metrics_node_client_errors_total{base_url=~\"$base_url\"}[1m])",
+              "format": "time_series",
+              "intervalFactor": 2,
+              "legendFormat": "{{base_url}}{{handler}}",
+              "refId": "A"
+            }
+          ],
+          "thresholds": [],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "Client Errors",
+          "tooltip": {
+            "shared": true,
+            "sort": 0,
+            "value_type": "individual"
+          },
+          "type": "graph",
+          "xaxis": {
+            "buckets": null,
+            "mode": "time",
+            "name": null,
+            "show": true,
+            "values": []
+          },
+          "yaxes": [
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": "0",
+              "show": true
+            },
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        },
+        {
+          "aliasColors": {},
+          "bars": false,
+          "dashLength": 10,
+          "dashes": false,
+          "datasource": "${DS_PROMETHEUS}",
+          "fill": 1,
+          "id": 20,
+          "legend": {
+            "alignAsTable": true,
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "null",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "spaceLength": 10,
+          "span": 6,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "expr": "increase(solr_metrics_node_server_errors_total{base_url=~\"$base_url\"}[1m])",
+              "format": "time_series",
+              "intervalFactor": 2,
+              "legendFormat": "{{base_url}}{{handler}}",
+              "refId": "A"
+            }
+          ],
+          "thresholds": [],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "Server Errors",
+          "tooltip": {
+            "shared": true,
+            "sort": 0,
+            "value_type": "individual"
+          },
+          "type": "graph",
+          "xaxis": {
+            "buckets": null,
+            "mode": "time",
+            "name": null,
+            "show": true,
+            "values": []
+          },
+          "yaxes": [
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": "0",
+              "show": true
+            },
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        },
+        {
+          "aliasColors": {},
+          "bars": false,
+          "dashLength": 10,
+          "dashes": false,
+          "datasource": "${DS_PROMETHEUS}",
+          "fill": 1,
+          "id": 18,
+          "legend": {
+            "alignAsTable": true,
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "null",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "spaceLength": 10,
+          "span": 6,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "expr": "increase(solr_metrics_node_errors_total{base_url=~\"$base_url\"}[1m])",
+              "format": "time_series",
+              "intervalFactor": 2,
+              "legendFormat": "{{base_url}}{{handler}}",
+              "refId": "A"
+            }
+          ],
+          "thresholds": [],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "Errors",
+          "tooltip": {
+            "shared": true,
+            "sort": 0,
+            "value_type": "individual"
+          },
+          "type": "graph",
+          "xaxis": {
+            "buckets": null,
+            "mode": "time",
+            "name": null,
+            "show": true,
+            "values": []
+          },
+          "yaxes": [
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": "0",
+              "show": true
+            },
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        },
+        {
+          "aliasColors": {},
+          "bars": false,
+          "dashLength": 10,
+          "dashes": false,
+          "datasource": "${DS_PROMETHEUS}",
+          "fill": 1,
+          "id": 21,
+          "legend": {
+            "alignAsTable": true,
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "null",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "spaceLength": 10,
+          "span": 6,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "expr": "increase(solr_metrics_node_timeouts_total{base_url=~\"$base_url\"}[1m])",
+              "format": "time_series",
+              "intervalFactor": 2,
+              "legendFormat": "{{base_url}}{{handler}}",
+              "refId": "A"
+            }
+          ],
+          "thresholds": [],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "Timeouts",
+          "tooltip": {
+            "shared": true,
+            "sort": 0,
+            "value_type": "individual"
+          },
+          "type": "graph",
+          "xaxis": {
+            "buckets": null,
+            "mode": "time",
+            "name": null,
+            "show": true,
+            "values": []
+          },
+          "yaxes": [
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": "0",
+              "show": true
+            },
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        },
+        {
+          "aliasColors": {},
+          "bars": false,
+          "dashLength": 10,
+          "dashes": false,
+          "datasource": "${DS_PROMETHEUS}",
+          "fill": 1,
+          "id": 23,
+          "legend": {
+            "alignAsTable": true,
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "null",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "spaceLength": 10,
+          "span": 6,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "expr": "solr_metrics_node_cores{base_url=~\"$base_url\"}",
+              "format": "time_series",
+              "intervalFactor": 2,
+              "legendFormat": "{{base_url}} {{item}}",
+              "refId": "A"
+            }
+          ],
+          "thresholds": [],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "Cores",
+          "tooltip": {
+            "shared": true,
+            "sort": 0,
+            "value_type": "individual"
+          },
+          "type": "graph",
+          "xaxis": {
+            "buckets": null,
+            "mode": "time",
+            "name": null,
+            "show": true,
+            "values": []
+          },
+          "yaxes": [
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": "0",
+              "show": true
+            },
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        },
+        {
+          "aliasColors": {},
+          "bars": false,
+          "dashLength": 10,
+          "dashes": false,
+          "datasource": "${DS_PROMETHEUS}",
+          "fill": 1,
+          "id": 24,
+          "legend": {
+            "alignAsTable": true,
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "null",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "spaceLength": 10,
+          "span": 6,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "expr": "solr_metrics_node_core_root_fs_bytes{base_url=~\"$base_url\"}",
+              "format": "time_series",
+              "intervalFactor": 2,
+              "legendFormat": "{{base_url}} {{item}}",
+              "refId": "A"
+            }
+          ],
+          "thresholds": [],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "Core Root File System",
+          "tooltip": {
+            "shared": true,
+            "sort": 0,
+            "value_type": "individual"
+          },
+          "type": "graph",
+          "xaxis": {
+            "buckets": null,
+            "mode": "time",
+            "name": null,
+            "show": true,
+            "values": []
+          },
+          "yaxes": [
+            {
+              "format": "decbytes",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": "0",
+              "show": true
+            },
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        },
+        {
+          "aliasColors": {},
+          "bars": false,
+          "dashLength": 10,
+          "dashes": false,
+          "datasource": "${DS_PROMETHEUS}",
+          "fill": 1,
+          "id": 25,
+          "legend": {
+            "alignAsTable": true,
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "null",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "spaceLength": 10,
+          "span": 6,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "expr": "increase(solr_metrics_node_thread_pool_completed_total{base_url=~\"$base_url\"}[1m])",
+              "format": "time_series",
+              "intervalFactor": 2,
+              "legendFormat": "{{base_url}} {{handler}} {{executor}}",
+              "refId": "A"
+            }
+          ],
+          "thresholds": [],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "Thread Pool Completed",
+          "tooltip": {
+            "shared": true,
+            "sort": 0,
+            "value_type": "individual"
+          },
+          "type": "graph",
+          "xaxis": {
+            "buckets": null,
+            "mode": "time",
+            "name": null,
+            "show": true,
+            "values": []
+          },
+          "yaxes": [
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": "0",
+              "show": true
+            },
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        },
+        {
+          "aliasColors": {},
+          "bars": false,
+          "dashLength": 10,
+          "dashes": false,
+          "datasource": "${DS_PROMETHEUS}",
+          "fill": 1,
+          "id": 26,
+          "legend": {
+            "alignAsTable": true,
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "null",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "spaceLength": 10,
+          "span": 6,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "expr": "increase(solr_metrics_node_thread_pool_submitted_total{base_url=~\"$base_url\"}[1m])",
+              "format": "time_series",
+              "intervalFactor": 2,
+              "legendFormat": "{{base_url}} {{handler}} {{executor}}",
+              "refId": "A"
+            }
+          ],
+          "thresholds": [],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "Thread Pool Submitted",
+          "tooltip": {
+            "shared": true,
+            "sort": 0,
+            "value_type": "individual"
+          },
+          "type": "graph",
+          "xaxis": {
+            "buckets": null,
+            "mode": "time",
+            "name": null,
+            "show": true,
+            "values": []
+          },
+          "yaxes": [
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": "0",
+              "show": true
+            },
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        },
+        {
+          "aliasColors": {},
+          "bars": false,
+          "dashLength": 10,
+          "dashes": false,
+          "datasource": "${DS_PROMETHEUS}",
+          "fill": 1,
+          "id": 27,
+          "legend": {
+            "alignAsTable": true,
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "rightSide": true,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "null",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "spaceLength": 10,
+          "span": 12,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "expr": "solr_metrics_node_thread_pool_running{base_url=~\"$base_url\"}",
+              "format": "time_series",
+              "intervalFactor": 2,
+              "legendFormat": "{{base_url}} {{handler}} {{executor}}",
+              "refId": "A"
+            }
+          ],
+          "thresholds": [],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "Thread Pool Running",
+          "tooltip": {
+            "shared": true,
+            "sort": 0,
+            "value_type": "individual"
+          },
+          "type": "graph",
+          "xaxis": {
+            "buckets": null,
+            "mode": "time",
+            "name": null,
+            "show": true,
+            "values": []
+          },
+          "yaxes": [
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": "0",
+              "show": true
+            },
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        },
+        {
+          "aliasColors": {},
+          "bars": false,
+          "dashLength": 10,
+          "dashes": false,
+          "datasource": "${DS_PROMETHEUS}",
+          "fill": 1,
+          "id": 28,
+          "legend": {
+            "alignAsTable": true,
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "rightSide": true,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "null",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "spaceLength": 10,
+          "span": 12,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "expr": "solr_metrics_node_connections{base_url=~\"$base_url\"}",
+              "format": "time_series",
+              "intervalFactor": 2,
+              "legendFormat": "{{base_url}} {{handler}} {{item}}",
+              "refId": "A"
+            }
+          ],
+          "thresholds": [],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "Connections",
+          "tooltip": {
+            "shared": true,
+            "sort": 0,
+            "value_type": "individual"
+          },
+          "type": "graph",
+          "xaxis": {
+            "buckets": null,
+            "mode": "time",
+            "name": null,
+            "show": true,
+            "values": []
+          },
+          "yaxes": [
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": "0",
+              "show": true
+            },
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        }
+      ],
+      "repeat": null,
+      "repeatIteration": null,
+      "repeatRowId": null,
+      "showTitle": true,
+      "title": "Node Metrics",
+      "titleSize": "h3"
+    },
+    {
+      "collapse": false,
+      "height": 250,
+      "panels": [
+        {
+          "aliasColors": {},
+          "bars": false,
+          "dashLength": 10,
+          "dashes": false,
+          "datasource": "${DS_PROMETHEUS}",
+          "fill": 1,
+          "id": 31,
+          "legend": {
+            "alignAsTable": true,
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "null",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "spaceLength": 10,
+          "span": 6,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "expr": "increase(solr_metrics_core_requests_total{base_url=~\"$base_url\"}[1m])",
+              "format": "time_series",
+              "intervalFactor": 2,
+              "legendFormat": "{{base_url}}/{{core}}{{handler}}",
+              "refId": "A"
+            }
+          ],
+          "thresholds": [],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "Requests",
+          "tooltip": {
+            "shared": true,
+            "sort": 0,
+            "value_type": "individual"
+          },
+          "type": "graph",
+          "xaxis": {
+            "buckets": null,
+            "mode": "time",
+            "name": null,
+            "show": true,
+            "values": []
+          },
+          "yaxes": [
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": "0",
+              "show": true
+            },
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        },
+        {
+          "aliasColors": {},
+          "bars": false,
+          "dashLength": 10,
+          "dashes": false,
+          "datasource": "${DS_PROMETHEUS}",
+          "fill": 1,
+          "id": 34,
+          "legend": {
+            "alignAsTable": true,
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "null",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "spaceLength": 10,
+          "span": 6,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "expr": "increase(solr_metrics_core_time_seconds_total{base_url=~\"$base_url\"}[1m])",
+              "format": "time_series",
+              "intervalFactor": 2,
+              "legendFormat": "{{base_url}}/{{core}}{{handler}}",
+              "refId": "A"
+            }
+          ],
+          "thresholds": [],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "Request Time",
+          "tooltip": {
+            "shared": true,
+            "sort": 0,
+            "value_type": "individual"
+          },
+          "type": "graph",
+          "xaxis": {
+            "buckets": null,
+            "mode": "time",
+            "name": null,
+            "show": true,
+            "values": []
+          },
+          "yaxes": [
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": "0",
+              "show": true
+            },
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        },
+        {
+          "aliasColors": {},
+          "bars": false,
+          "dashLength": 10,
+          "dashes": false,
+          "datasource": "${DS_PROMETHEUS}",
+          "fill": 1,
+          "id": 29,
+          "legend": {
+            "alignAsTable": true,
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "null",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "spaceLength": 10,
+          "span": 6,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "expr": "increase(solr_metrics_core_client_errors_total{base_url=~\"$base_url\"}[1m])",
+              "format": "time_series",
+              "intervalFactor": 2,
+              "legendFormat": "{{base_url}}/{{core}}{{handler}}",
+              "refId": "A"
+            }
+          ],
+          "thresholds": [],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "Client Errors",
+          "tooltip": {
+            "shared": true,
+            "sort": 0,
+            "value_type": "individual"
+          },
+          "type": "graph",
+          "xaxis": {
+            "buckets": null,
+            "mode": "time",
+            "name": null,
+            "show": true,
+            "values": []
+          },
+          "yaxes": [
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": "0",
+              "show": true
+            },
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        },
+        {
+          "aliasColors": {},
+          "bars": false,
+          "dashLength": 10,
+          "dashes": false,
+          "datasource": "${DS_PROMETHEUS}",
+          "fill": 1,
+          "id": 32,
+          "legend": {
+            "alignAsTable": true,
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "null",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "spaceLength": 10,
+          "span": 6,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "expr": "increase(solr_metrics_core_server_errors_total{base_url=~\"$base_url\"}[1m])",
+              "format": "time_series",
+              "intervalFactor": 2,
+              "legendFormat": "{{base_url}}/{{core}}{{handler}}",
+              "refId": "A"
+            }
+          ],
+          "thresholds": [],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "Server Errors",
+          "tooltip": {
+            "shared": true,
+            "sort": 0,
+            "value_type": "individual"
+          },
+          "type": "graph",
+          "xaxis": {
+            "buckets": null,
+            "mode": "time",
+            "name": null,
+            "show": true,
+            "values": []
+          },
+          "yaxes": [
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": "0",
+              "show": true
+            },
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        },
+        {
+          "aliasColors": {},
+          "bars": false,
+          "dashLength": 10,
+          "dashes": false,
+          "datasource": "${DS_PROMETHEUS}",
+          "fill": 1,
+          "id": 30,
+          "legend": {
+            "alignAsTable": true,
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "null",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "spaceLength": 10,
+          "span": 6,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "expr": "increase(solr_metrics_core_errors_total{base_url=~\"$base_url\"}[1m])",
+              "format": "time_series",
+              "intervalFactor": 2,
+              "legendFormat": "{{base_url}}/{{core}}{{handler}}",
+              "refId": "A"
+            }
+          ],
+          "thresholds": [],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "Errors",
+          "tooltip": {
+            "shared": true,
+            "sort": 0,
+            "value_type": "individual"
+          },
+          "type": "graph",
+          "xaxis": {
+            "buckets": null,
+            "mode": "time",
+            "name": null,
+            "show": true,
+            "values": []
+          },
+          "yaxes": [
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": "0",
+              "show": true
+            },
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        },
+        {
+          "aliasColors": {},
+          "bars": false,
+          "dashLength": 10,
+          "dashes": false,
+          "datasource": "${DS_PROMETHEUS}",
+          "fill": 1,
+          "id": 33,
+          "legend": {
+            "alignAsTable": true,
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "null",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "spaceLength": 10,
+          "span": 6,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "expr": "increase(solr_metrics_core_timeouts_total{base_url=~\"$base_url\"}[1m])",
+              "format": "time_series",
+              "intervalFactor": 2,
+              "legendFormat": "{{base_url}}/{{core}}{{handler}}",
+              "refId": "A"
+            }
+          ],
+          "thresholds": [],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "Timeouts",
+          "tooltip": {
+            "shared": true,
+            "sort": 0,
+            "value_type": "individual"
+          },
+          "type": "graph",
+          "xaxis": {
+            "buckets": null,
+            "mode": "time",
+            "name": null,
+            "show": true,
+            "values": []
+          },
+          "yaxes": [
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": "0",
+              "show": true
+            },
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        },
+        {
+          "aliasColors": {},
+          "bars": false,
+          "dashLength": 10,
+          "dashes": false,
+          "datasource": "${DS_PROMETHEUS}",
+          "fill": 1,
+          "id": 35,
+          "legend": {
+            "alignAsTable": true,
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "null",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "spaceLength": 10,
+          "span": 6,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "expr": "increase(solr_metrics_core_field_cache_total{base_url=~\"$base_url\"}[1m])",
+              "format": "time_series",
+              "intervalFactor": 2,
+              "legendFormat": "{{base_url}}/{{core}}",
+              "refId": "A"
+            }
+          ],
+          "thresholds": [],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "Field Cache",
+          "tooltip": {
+            "shared": true,
+            "sort": 0,
+            "value_type": "individual"
+          },
+          "type": "graph",
+          "xaxis": {
+            "buckets": null,
+            "mode": "time",
+            "name": null,
+            "show": true,
+            "values": []
+          },
+          "yaxes": [
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": "0",
+              "show": true
+            },
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        },
+        {
+          "aliasColors": {},
+          "bars": false,
+          "dashLength": 10,
+          "dashes": false,
+          "datasource": "${DS_PROMETHEUS}",
+          "fill": 1,
+          "id": 36,
+          "legend": {
+            "alignAsTable": true,
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "null",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "spaceLength": 10,
+          "span": 6,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "expr": "solr_metrics_core_searcher_cache{base_url=~\"$base_url\"}",
+              "format": "time_series",
+              "intervalFactor": 2,
+              "legendFormat": "{{base_url}}/{{core}} {{type}} {{item}}",
+              "refId": "A"
+            }
+          ],
+          "thresholds": [],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "Searcher Cache",
+          "tooltip": {
+            "shared": true,
+            "sort": 0,
+            "value_type": "individual"
+          },
+          "type": "graph",
+          "xaxis": {
+            "buckets": null,
+            "mode": "time",
+            "name": null,
+            "show": true,
+            "values": []
+          },
+          "yaxes": [
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": "0",
+              "show": true
+            },
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        },
+        {
+          "aliasColors": {},
+          "bars": false,
+          "dashLength": 10,
+          "dashes": false,
+          "datasource": "${DS_PROMETHEUS}",
+          "fill": 1,
+          "id": 37,
+          "legend": {
+            "alignAsTable": true,
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "null",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "spaceLength": 10,
+          "span": 6,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "expr": "solr_metrics_core_searcher_warmup_time_seconds{base_url=~\"$base_url\"}",
+              "format": "time_series",
+              "intervalFactor": 2,
+              "legendFormat": "{{base_url}}/{{core}} {{type}}",
+              "refId": "A"
+            }
+          ],
+          "thresholds": [],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "Searcher Warm Up Time",
+          "tooltip": {
+            "shared": true,
+            "sort": 0,
+            "value_type": "individual"
+          },
+          "type": "graph",
+          "xaxis": {
+            "buckets": null,
+            "mode": "time",
+            "name": null,
+            "show": true,
+            "values": []
+          },
+          "yaxes": [
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            },
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        },
+        {
+          "aliasColors": {},
+          "bars": false,
+          "dashLength": 10,
+          "dashes": false,
+          "datasource": "${DS_PROMETHEUS}",
+          "fill": 1,
+          "id": 38,
+          "legend": {
+            "alignAsTable": true,
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "null",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "spaceLength": 10,
+          "span": 6,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "expr": "increase(solr_metrics_core_searcher_cumulative_cache_total{base_url=~\"$base_url\"}[1m])",
+              "format": "time_series",
+              "intervalFactor": 2,
+              "legendFormat": "{{base_url}}/{{core}} {{type}} {{item}}",
+              "refId": "A"
+            }
+          ],
+          "thresholds": [],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "Searcher Cumulative Cache",
+          "tooltip": {
+            "shared": true,
+            "sort": 0,
+            "value_type": "individual"
+          },
+          "type": "graph",
+          "xaxis": {
+            "buckets": null,
+            "mode": "time",
+            "name": null,
+            "show": true,
+            "values": []
+          },
+          "yaxes": [
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": "0",
+              "show": true
+            },
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        },
+        {
+          "aliasColors": {},
+          "bars": false,
+          "dashLength": 10,
+          "dashes": false,
+          "datasource": "${DS_PROMETHEUS}",
+          "fill": 1,
+          "id": 39,
+          "legend": {
+            "alignAsTable": true,
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "null",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "spaceLength": 10,
+          "span": 6,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "expr": "solr_metrics_core_fs_bytes{base_url=~\"$base_url\"}",
+              "format": "time_series",
+              "intervalFactor": 2,
+              "legendFormat": "{{base_url}}/{{core}}",
+              "refId": "A"
+            }
+          ],
+          "thresholds": [],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "File System",
+          "tooltip": {
+            "shared": true,
+            "sort": 0,
+            "value_type": "individual"
+          },
+          "type": "graph",
+          "xaxis": {
+            "buckets": null,
+            "mode": "time",
+            "name": null,
+            "show": true,
+            "values": []
+          },
+          "yaxes": [
+            {
+              "format": "decbytes",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": "0",
+              "show": true
+            },
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        },
+        {
+          "aliasColors": {},
+          "bars": false,
+          "dashLength": 10,
+          "dashes": false,
+          "datasource": "${DS_PROMETHEUS}",
+          "fill": 1,
+          "id": 40,
+          "legend": {
+            "alignAsTable": true,
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "null",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "spaceLength": 10,
+          "span": 6,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "expr": "solr_metrics_core_index_size_bytes{base_url=~\"$base_url\"}",
+              "format": "time_series",
+              "intervalFactor": 2,
+              "legendFormat": "{{base_url}}/{{core}}",
+              "refId": "A"
+            }
+          ],
+          "thresholds": [],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "Index Size",
+          "tooltip": {
+            "shared": true,
+            "sort": 0,
+            "value_type": "individual"
+          },
+          "type": "graph",
+          "xaxis": {
+            "buckets": null,
+            "mode": "time",
+            "name": null,
+            "show": true,
+            "values": []
+          },
+          "yaxes": [
+            {
+              "format": "decbytes",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": "0",
+              "show": true
+            },
+            {
+              "format": "short",
+              "label": null,
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        },
+        {
+          "aliasColors": {},
+          "bars": false,
+          "dashLength": 10,
+          "dashes": false,
+          "datasource": "${DS_PROMETHEUS}",
+          "fill": 1,
+          "id": 41,
+          "legend": {
+        

<TRUNCATED>

Re: [1/7] lucene-solr:master: SOLR-11795: Add Solr metrics exporter for Prometheus

Posted by Koji Sekiguchi <ko...@rondhuit.com>.
Before committing this, I did ant precommit and I saw a message "Source checkout is dirty..." but I 
passed over it because I thought I should accept it as solr/contrib/prometheus-exporter is a new 
directory.

I fixed some failures but it still has errors that inform "MISSING sha1 checksum file for 
solr/contrib/prometheus-exporter/lib/*.jar"

I think I don't have time to fix them now. I'll revert SOLR-11795 and try it in the later of this week.

I deeply apologize for the inconvenience.


On 2018/02/20 22:34, Koji Sekiguchi wrote:
> I'm sorry. Let me check...
> 
> 
> On 2018/02/20 20:50, Andrzej Białecki wrote:
>> Builds on jenkins are failing due to precommit failures in this code...
>>
>>> On 20 Feb 2018, at 09:47, koji@apache.org <ma...@apache.org> wrote:
>>>
>>> Repository: lucene-solr
>>> Updated Branches:
>>>  refs/heads/master dfc0fe86e -> 4bfcbc5c6
>>>
>>>
>>> http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/config/SolrQueryConfigTest.java 
>>>
>>> ----------------------------------------------------------------------
>>> diff --git 
>>> a/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/config/SolrQueryConfigTest.java 
>>> b/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/config/SolrQueryConfigTest.java 
>>>
>>> new file mode 100644
>>> index 0000000..c62d354
>>> --- /dev/null
>>> +++ 
>>> b/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/config/SolrQueryConfigTest.java 
>>>
>>> @@ -0,0 +1,121 @@
>>> +/*
>>> + * 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.prometheus.scraper.config;
>>> +
>>> +import org.apache.solr.SolrTestCaseJ4;
>>> +import org.junit.Test;
>>> +
>>> +import java.util.ArrayList;
>>> +import java.util.Arrays;
>>> +import java.util.LinkedHashMap;
>>> +import java.util.List;
>>> +
>>> +/**
>>> + * Unit test for SolrQueryConfig.
>>> + */
>>> +public class SolrQueryConfigTest extends SolrTestCaseJ4 {
>>> +  @Test
>>> +  public void testQueryConfig() throws Exception {
>>> +    SolrQueryConfig queryConfig = new SolrQueryConfig();
>>> +
>>> +    assertNotNull(queryConfig);
>>> +  }
>>> +
>>> +  @Test
>>> +  public void testGetCollection() throws Exception {
>>> +    SolrQueryConfig queryConfig = new SolrQueryConfig();
>>> +
>>> +    String expected = "";
>>> +    String actual = queryConfig.getCollection();
>>> +    assertEquals(expected, actual);
>>> +  }
>>> +
>>> +  @Test
>>> +  public void testSetCollection() throws Exception {
>>> +    SolrQueryConfig queryConfig = new SolrQueryConfig();
>>> +
>>> +    queryConfig.setCollection("collection1");
>>> +
>>> +    String expected = "collection1";
>>> +    String actual = queryConfig.getCollection();
>>> +    assertEquals(expected, actual);
>>> +  }
>>> +
>>> +  @Test
>>> +  public void testGetPath() throws Exception {
>>> +    SolrQueryConfig queryConfig = new SolrQueryConfig();
>>> +
>>> +    String expected = "";
>>> +    String actual = queryConfig.getPath();
>>> +    assertEquals(expected, actual);
>>> +  }
>>> +
>>> +  @Test
>>> +  public void testSetPath() throws Exception {
>>> +    SolrQueryConfig queryConfig = new SolrQueryConfig();
>>> +
>>> +    queryConfig.setPath("/select");
>>> +
>>> +    String expected = "/select";
>>> +    String actual = queryConfig.getPath();
>>> +    assertEquals(expected, actual);
>>> +  }
>>> +
>>> +  @Test
>>> +  public void testGetParams() throws Exception {
>>> +    SolrQueryConfig queryConfig = new SolrQueryConfig();
>>> +
>>> +    List<LinkedHashMap<String, String>> expected = new ArrayList<>();
>>> +    List<LinkedHashMap<String, String>> actual = queryConfig.getParams();
>>> +    assertEquals(expected, actual);
>>> +  }
>>> +
>>> +  @Test
>>> +  public void testSetParams() throws Exception {
>>> +    SolrQueryConfig queryConfig = new SolrQueryConfig();
>>> +
>>> +    LinkedHashMap<String,String> param1 = new LinkedHashMap<>();
>>> +    param1.put("q", "*:*");
>>> +
>>> +    LinkedHashMap<String,String> param2 = new LinkedHashMap<>();
>>> +    param2.put("facet", "on");
>>> +
>>> +    queryConfig.setParams(Arrays.asList(param1, param2));
>>> +
>>> +    List<LinkedHashMap<String, String>> expected = Arrays.asList(param1, param2);
>>> +    List<LinkedHashMap<String, String>> actual = queryConfig.getParams();
>>> +    assertEquals(expected, actual);
>>> +  }
>>> +
>>> +  @Test
>>> +  public void testGetParamsString() throws Exception {
>>> +    SolrQueryConfig queryConfig = new SolrQueryConfig();
>>> +
>>> +    LinkedHashMap<String,String> param1 = new LinkedHashMap<>();
>>> +    param1.put("q", "*:*");
>>> +    param1.put("fq", "manu:apple");
>>> +
>>> +    LinkedHashMap<String,String> param2 = new LinkedHashMap<>();
>>> +    param2.put("facet", "on");
>>> +
>>> +    queryConfig.setParams(Arrays.asList(param1, param2));
>>> +
>>> +    String expected = "q=*:*&fq=manu:apple&facet=on";
>>> +    String actual = queryConfig.getParamsString();
>>> +    assertEquals(expected, actual);
>>> +  }
>>> +}
>>>
>>> http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/config/SolrScraperConfigTest.java 
>>>
>>> ----------------------------------------------------------------------
>>> diff --git 
>>> a/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/config/SolrScraperConfigTest.java 
>>> b/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/config/SolrScraperConfigTest.java 
>>>
>>> new file mode 100644
>>> index 0000000..79d1204
>>> --- /dev/null
>>> +++ 
>>> b/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/config/SolrScraperConfigTest.java 
>>>
>>> @@ -0,0 +1,86 @@
>>> +/*
>>> + * 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.prometheus.scraper.config;
>>> +
>>> +import org.apache.solr.prometheus.collector.config.SolrCollectorConfig;
>>> +import org.apache.solr.SolrTestCaseJ4;
>>> +import org.junit.Test;
>>> +import org.yaml.snakeyaml.Yaml;
>>> +
>>> +import java.io.FileReader;
>>> +import java.util.ArrayList;
>>> +import java.util.List;
>>> +
>>> +/**
>>> + * Unit test for SolrScraperConfig.
>>> + */
>>> +public class SolrScraperConfigTest extends SolrTestCaseJ4 {
>>> +  @Test
>>> +  public void testScraperConfig() throws Exception {
>>> +    String configFile = getFile("conf/config.yml").getAbsolutePath();
>>> +
>>> +    SolrCollectorConfig config = new Yaml().loadAs(new FileReader(configFile), 
>>> SolrCollectorConfig.class);
>>> +
>>> +    SolrScraperConfig scraperConfig = config.getMetrics();
>>> +
>>> +    assertNotNull(scraperConfig);
>>> +  }
>>> +
>>> +  @Test
>>> +  public void testGetJsonQueries() throws Exception {
>>> +    String configFile = getFile("conf/config.yml").getAbsolutePath();
>>> +
>>> +    SolrCollectorConfig collectorConfig = new Yaml().loadAs(new FileReader(configFile), 
>>> SolrCollectorConfig.class);
>>> +
>>> +    SolrScraperConfig scraperConfig = collectorConfig.getMetrics();
>>> +
>>> +    assertNotNull(scraperConfig.getJsonQueries());
>>> +  }
>>> +
>>> +  @Test
>>> +  public void testSetJsonQueries() throws Exception {
>>> +    List<String> jsonQueries = new ArrayList<>();
>>> +
>>> +    SolrScraperConfig scraperConfig = new SolrScraperConfig();
>>> +
>>> +    scraperConfig.setJsonQueries(jsonQueries);
>>> +
>>> +    assertNotNull(scraperConfig.getJsonQueries());
>>> +  }
>>> +
>>> +  @Test
>>> +  public void testGetQueryConfig() throws Exception {
>>> +    String configFile = getFile("conf/config.yml").getAbsolutePath();
>>> +
>>> +    SolrCollectorConfig collectorConfig = new Yaml().loadAs(new FileReader(configFile), 
>>> SolrCollectorConfig.class);
>>> +
>>> +    SolrScraperConfig scraperConfig = collectorConfig.getMetrics();
>>> +
>>> +    assertNotNull(scraperConfig.getQuery());
>>> +  }
>>> +
>>> +  @Test
>>> +  public void testSetQueryConfig() throws Exception {
>>> +    SolrQueryConfig queryConfig = new SolrQueryConfig();
>>> +
>>> +    SolrScraperConfig scraperConfig = new SolrScraperConfig();
>>> +
>>> +    scraperConfig.setQuery(queryConfig);
>>> +
>>> +    assertNotNull(scraperConfig.getQuery());
>>> +  }
>>> +}
>>>
>>> http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/solr-ref-guide/src/images/monitoring-solr-with-prometheus-and-grafana/grafana-solr-dashboard.png 
>>>
>>> ----------------------------------------------------------------------
>>> diff --git 
>>> a/solr/solr-ref-guide/src/images/monitoring-solr-with-prometheus-and-grafana/grafana-solr-dashboard.png 
>>> b/solr/solr-ref-guide/src/images/monitoring-solr-with-prometheus-and-grafana/grafana-solr-dashboard.png 
>>>
>>> new file mode 100644
>>> index 0000000..69f21a4
>>> Binary files /dev/null and 
>>> b/solr/solr-ref-guide/src/images/monitoring-solr-with-prometheus-and-grafana/grafana-solr-dashboard.png 
>>> differ
>>>
>>> http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/solr-ref-guide/src/images/monitoring-solr-with-prometheus-and-grafana/solr-exporter-diagram.png 
>>>
>>> ----------------------------------------------------------------------
>>> diff --git 
>>> a/solr/solr-ref-guide/src/images/monitoring-solr-with-prometheus-and-grafana/solr-exporter-diagram.png 
>>> b/solr/solr-ref-guide/src/images/monitoring-solr-with-prometheus-and-grafana/solr-exporter-diagram.png 
>>>
>>> new file mode 100644
>>> index 0000000..96efece
>>> Binary files /dev/null and 
>>> b/solr/solr-ref-guide/src/images/monitoring-solr-with-prometheus-and-grafana/solr-exporter-diagram.png 
>>> differ
>>>
>>> http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/solr-ref-guide/src/monitoring-solr-with-prometheus-and-grafana.adoc 
>>>
>>> ----------------------------------------------------------------------
>>> diff --git a/solr/solr-ref-guide/src/monitoring-solr-with-prometheus-and-grafana.adoc 
>>> b/solr/solr-ref-guide/src/monitoring-solr-with-prometheus-and-grafana.adoc
>>> new file mode 100644
>>> index 0000000..1ac55a2
>>> --- /dev/null
>>> +++ b/solr/solr-ref-guide/src/monitoring-solr-with-prometheus-and-grafana.adoc
>>> @@ -0,0 +1,250 @@
>>> += Monitoring Solr with Prometheus and Grafana
>>> +// 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.
>>> +
>>> +You can monitor Solr using solr-exporter that exposes Solr's metrics to 
>>> https://prometheus.io[Prometheus], and visualize metrics using https://grafana.com[Grafana].
>>> +
>>> +It allows users to monitor not only Solr metrics which come from 
>>> <<metrics-reporting.adoc#metrics-api,Metrics API>> but also facet counts which come from 
>>> <<searching.adoc#searching,Searching>>.
>>> +
>>> +.solr-exporter Diagram
>>> +image::images/monitoring-solr-with-prometheus-and-grafana/solr-exporter-diagram.png[image,width=600] 
>>>
>>> +
>>> +This feature is experimental status.
>>> +
>>> +== Running solr-exporter
>>> +
>>> +You can start solr-exporter by running `./bin/solr-exporter` from the solr-exporter directory.
>>> +
>>> +[source,plain]
>>> +----
>>> +$ cd ./contrib/prometheus-exporter
>>> +$ ./bin/solr-exporter -p 9983 -b http://localhost:8983/solr -f ./conf/config.yml -n 8
>>> +----
>>> +
>>> +If you are on Windows platform, you can start solr-exporter by running `.\bin\solr-exporter.cmd` 
>>> instead.
>>> +
>>> +[source,plain]
>>> +----
>>> +> cd .\contrib\prometheus
>>> +> .\bin\solr-exporter.cmd -p 9983 -b http://localhost:8983/solr -f .\conf\config.yml -n 8
>>> +----
>>> +
>>> +You can also connect to Solr in SolrCloud mode like this.
>>> +
>>> +[source,plain]
>>> +----
>>> +$ cd ./contrib/prometheus
>>> +$ ./bin/solr-exporter -p 9983 -z localhost:2181/solr -f ./conf/config.yml -n 16
>>> +----
>>> +
>>> +See command help:
>>> +
>>> +[source,plain]
>>> +----
>>> +$ ./bin/solr-exporter -h
>>> +usage: SolrCollector [-h] [-v] [-p PORT] [-b BASE_URL] [-z ZK_HOST] [-f CONFIG]
>>> +                     [-n NUM_THREADS]
>>> +
>>> +Prometheus exporter for Apache Solr.
>>> +
>>> +optional arguments:
>>> +  -h, --help             show this help message and exit
>>> +  -p PORT, --port PORT   solr-exporter listen port
>>> +  -b BASE_URL, --baseurl BASE_URL
>>> +                         specify Solr base URL when connecting  to Solr in standalone mode (for
>>> +                         example 'http://localhost:8983/solr')
>>> +  -z ZK_HOST, --zkhost ZK_HOST
>>> +                         specify  ZooKeeper  connection  string  when  connecting  to  Solr  in
>>> +                         SolrCloud mode (for example 'localhost:2181/solr')
>>> +  -f CONFIG, --config-file CONFIG
>>> +                         specify configuration file
>>> +  -n NUM_THREADS, --num-thread NUM_THREADS
>>> +                         specify number of threads
>>> +----
>>> +
>>> +The Solr's metrics exposed by solr-exporter can see at the following URL.
>>> +
>>> +http://localhost:9983/metrics[http://localhost:9983/metrics]
>>> +
>>> +
>>> +== Configuration
>>> +
>>> +The configuration is in `./config/config.yml`. An example with all possible options:
>>> +
>>> +[source,plain]
>>> +----
>>> +ping:
>>> +  query:
>>> +    path: /admin/ping
>>> +  jsonQueries:
>>> +    - |-
>>> +      . as $object | $object |
>>> +      (if $object.status == "OK" then 1.0 else 0.0 end) as $value |
>>> +      {
>>> +        name         : "solr_ping",
>>> +        type         : "GAUGE",
>>> +        help         : "See following URL: https://lucene.apache.org/solr/guide/ping.html",
>>> +        label_names  : [],
>>> +        label_values : [],
>>> +        value        : $value
>>> +      }
>>> +
>>> +metrics:
>>> +  query:
>>> +    path: /admin/metrics
>>> +    params:
>>> +      - group: 'all'
>>> +      - type: 'all'
>>> +      - prefix: ''
>>> +      - property: ''
>>> +  jsonQueries:
>>> +    # solr_metrics_jetty_response_count
>>> +    - |-
>>> +      .metrics["solr.jetty"] | to_entries | .[] | select(.key | 
>>> startswith("org.eclipse.jetty.server.handler.DefaultHandler")) | select(.key | 
>>> endswith("xx-responses")) as $object |
>>> +      $object.key | split(".") | last | split("-") | first as $status |
>>> +      $object.value.count as $value |
>>> +      {
>>> +        name         : "solr_metrics_jetty_response_count",
>>> +        type         : "gauge",
>>> +        help         : "See following URL: 
>>> https://lucene.apache.org/solr/guide/metrics-reporting.html",
>>> +        label_names  : ["status"],
>>> +        label_values : [$status],
>>> +        value        : $value
>>> +      }
>>> +
>>> +...
>>> +
>>> +collections:
>>> +  query:
>>> +    path: /admin/collections
>>> +    params:
>>> +      - action: 'CLUSTERSTATUS'
>>> +  jsonQueries:
>>> +    # solr_collections_cluster_status_live_nodes
>>> +    - |-
>>> +      .cluster.live_nodes | length as $value|
>>> +      {
>>> +        name         : "solr_collections_cluster_status_live_nodes",
>>> +        type         : "gauge",
>>> +        help         : "See following URL: 
>>> https://lucene.apache.org/solr/guide/collections-api.html#clusterstatus",
>>> +        label_names  : [],
>>> +        label_values : [],
>>> +        value        : $value
>>> +      }
>>> +
>>> +...
>>> +
>>> +queries:
>>> +  - query:
>>> +      collection: collection1
>>> +      path: /select
>>> +      params:
>>> +        - q: "*:*"
>>> +        - start: 0
>>> +        - rows: 0
>>> +        - json.facet: |-
>>> +            {
>>> +              category: {
>>> +                type: terms,
>>> +                field: cat
>>> +              }
>>> +            }
>>> +    jsonQueries:
>>> +      # solr_facets_category
>>> +      - |-
>>> +        .facets.category.buckets[] as $object |
>>> +        $object.val as $term |
>>> +        $object.count as $value |
>>> +        {
>>> +          name         : "solr_facets_category",
>>> +          type         : "gauge",
>>> +          help         : "Category facets",
>>> +          label_names  : ["term"],
>>> +          label_values : [$term],
>>> +          value        : $value
>>> +        }
>>> +----
>>> +
>>> +|===
>>> +|Name|Description
>>> +
>>> +|ping|Scrape <<ping.adoc#ping,Ping>> response.
>>> +|metrics|Scrape <<metrics-reporting.adoc#metrics-api,Metrics API>> response.
>>> +|collections|Scrape <<collections-api.adoc#collections-api,Collections API>> response.
>>> +|queries|Scrape <<searching.adoc#searching,Search API>> response.
>>> +|*.query|Query parameter for each features. You can specify `collection`, `core`, `path`, and 
>>> `params`.
>>> +|*.jsonQueries|JSON Query that is jq syntax. For more details, see 
>>> https://stedolan.github.io/jq/manual/[https://stedolan.github.io/jq/manual/].
>>> +|===
>>> +
>>> +jq query has to output JSON in the following format.
>>> +
>>> +[source,json]
>>> +----
>>> +{
>>> +  name         : "solr_ping",
>>> +  type         : "GAUGE",
>>> +  help         : "See following URL: https://lucene.apache.org/solr/guide/ping.html",
>>> +  label_names  : ["base_url","core"],
>>> +  label_values : ["http://localhost:8983/solr","collection1"],
>>> +  value        : 1.0
>>> +}
>>> +----
>>> +
>>> +It will be converted to the following exposition format.
>>> +
>>> +[source,plain]
>>> +----
>>> +# TYPE solr_ping gauge
>>> +# HELP solr_ping See following URL: https://lucene.apache.org/solr/guide/ping.html
>>> +solr_ping{base_url="http://localhost:8983/solr",core="collection1"} 1.0
>>> +----
>>> +
>>> +|===
>>> +|Name|Description
>>> +
>>> +|name|The metric name to set. For more details, see 
>>> https://prometheus.io/docs/practices/naming/[https://prometheus.io/docs/practices/naming/].
>>> +|type|The type of the metric, can be `COUNTER`, `GAUGE`, `SUMMARY`, `HISTOGRAM` or `UNTYPED`. 
>>> For more detauils, see 
>>> https://prometheus.io/docs/concepts/metric_types/[https://prometheus.io/docs/concepts/metric_types/]. 
>>>
>>> +|help|Help text for the metric.
>>> +|label_names|Label names for the metric. For more details, see 
>>> https://prometheus.io/docs/practices/naming/[https://prometheus.io/docs/practices/naming/].
>>> +|label_values|Label values for the metric. For more details, see 
>>> https://prometheus.io/docs/practices/naming/[https://prometheus.io/docs/practices/naming/].
>>> +|value|Value for the metric. Value must be set to Double type.
>>> +|===
>>> +
>>> +
>>> +== Prometheus Settings
>>> +
>>> +You need to specify the solr-exporter listen address into `scrape_configs` in `prometheus.yml`. 
>>> See following example:
>>> +
>>> +[source,plain]
>>> +----
>>> +scrape_configs:
>>> +  - job_name: 'solr'
>>> +    static_configs:
>>> +      - targets: ['localhost:9983']
>>> +----
>>> +
>>> +When you apply the above settings to prometheus, it will start to pull Solr's metrics from 
>>> solr-exporter.
>>> +
>>> +
>>> +== Grafana Dashboard
>>> +
>>> +A Grafana sample dashboard is provided at the following JSON file.
>>> +
>>> +`./conf/grafana-solr-dashboard.json`
>>> +
>>> +.Grafana Dashboard
>>> +image::images/monitoring-solr-with-prometheus-and-grafana/grafana-solr-dashboard.png[image,width=800] 
>>>
>>>
>>> http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/solr-ref-guide/src/monitoring-solr.adoc 
>>>
>>> ----------------------------------------------------------------------
>>> diff --git a/solr/solr-ref-guide/src/monitoring-solr.adoc 
>>> b/solr/solr-ref-guide/src/monitoring-solr.adoc
>>> index 0576e53..2fb7077 100644
>>> --- a/solr/solr-ref-guide/src/monitoring-solr.adoc
>>> +++ b/solr/solr-ref-guide/src/monitoring-solr.adoc
>>> @@ -1,5 +1,5 @@
>>> = Monitoring Solr
>>> -:page-children: metrics-reporting, mbean-request-handler, configuring-logging, 
>>> using-jmx-with-solr, performance-statistics-reference
>>> +:page-children: metrics-reporting, mbean-request-handler, configuring-logging, 
>>> using-jmx-with-solr, monitoring-solr-with-prometheus-and-grafana, performance-statistics-reference
>>> // 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
>>> @@ -30,6 +30,8 @@ Common administrative tasks include:
>>>
>>> <<using-jmx-with-solr.adoc#using-jmx-with-solr,Using JMX with Solr>>: Describes how to use Java 
>>> Management Extensions with Solr.
>>>
>>> +<<monitoring-solr-with-prometheus-and-grafana.adoc#monitoring-solr-with-prometheus-and-grafana,Monitoring 
>>> Solr with Prometheus and Grafana>>: Describes how to monitor Solr with Prometheus and Grafana.
>>> +
>>> <<performance-statistics-reference.adoc#performance-statistics-reference,Performance Statistics 
>>> Reference>>: Additional information on statistics returned from JMX.
>>>
>>>
>>>
>>
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@lucene.apache.org
> For additional commands, e-mail: dev-help@lucene.apache.org
> 
> 

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@lucene.apache.org
For additional commands, e-mail: dev-help@lucene.apache.org


Re: [1/7] lucene-solr:master: SOLR-11795: Add Solr metrics exporter for Prometheus

Posted by Koji Sekiguchi <ko...@rondhuit.com>.
Thanks for letting me know this. I'll fix it in the next patch...


On 2018/02/20 23:55, Cassandra Targett wrote:
> Ref Guide builds are also failing due to duplicate section headings on two pages.
> 
> https://builds.apache.org/job/Solr-reference-guide-master/5499/console:
> 
> build-site:
>       [java] ID occurs multiple times: configuration
>       [java]  ... file:/home/jenkins/jenkins-slave/workspace/Solr-reference-guide-master/solr/build/solr-ref-guide/html-site/monitoring-solr-with-prometheus-and-grafana.html
>       [java]  ... file:/home/jenkins/jenkins-slave/workspace/Solr-reference-guide-master/solr/build/solr-ref-guide/html-site/parallel-sql-interface.html
> 
> 
> This will cause links between sections of the PDF to go to the wrong place, so each section must be 
> unique. I'd suggest in this case possibly changing the new page section heading "Configuration" to 
> "solr-exporter Configuration" or something similar.
> 
> 
> On Tue, Feb 20, 2018 at 7:34 AM, Koji Sekiguchi <koji.sekiguchi@rondhuit.com 
> <ma...@rondhuit.com>> wrote:
> 
>     I'm sorry. Let me check...
> 
> 
>     On 2018/02/20 20:50, Andrzej Białecki wrote:
> 
>         Builds on jenkins are failing due to precommit failures in this code...
> 
>             On 20 Feb 2018, at 09:47, koji@apache.org <ma...@apache.org>
>             <mailto:koji@apache.org <ma...@apache.org>> wrote:
> 
>             Repository: lucene-solr
>             Updated Branches:
>               refs/heads/master dfc0fe86e -> 4bfcbc5c6
> 
> 
>             http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/config/SolrQueryConfigTest.java
>             <http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/config/SolrQueryConfigTest.java>
>             ----------------------------------------------------------------------
>             diff --git
>             a/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/config/SolrQueryConfigTest.java
>             b/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/config/SolrQueryConfigTest.java
>             new file mode 100644
>             index 0000000..c62d354
>             --- /dev/null
>             +++
>             b/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/config/SolrQueryConfigTest.java
>             @@ -0,0 +1,121 @@
>             +/*
>             + * 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 <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.prometheus.scraper.config;
>             +
>             +import org.apache.solr.SolrTestCaseJ4;
>             +import org.junit.Test;
>             +
>             +import java.util.ArrayList;
>             +import java.util.Arrays;
>             +import java.util.LinkedHashMap;
>             +import java.util.List;
>             +
>             +/**
>             + * Unit test for SolrQueryConfig.
>             + */
>             +public class SolrQueryConfigTest extends SolrTestCaseJ4 {
>             +  @Test
>             +  public void testQueryConfig() throws Exception {
>             +    SolrQueryConfig queryConfig = new SolrQueryConfig();
>             +
>             +    assertNotNull(queryConfig);
>             +  }
>             +
>             +  @Test
>             +  public void testGetCollection() throws Exception {
>             +    SolrQueryConfig queryConfig = new SolrQueryConfig();
>             +
>             +    String expected = "";
>             +    String actual = queryConfig.getCollection();
>             +    assertEquals(expected, actual);
>             +  }
>             +
>             +  @Test
>             +  public void testSetCollection() throws Exception {
>             +    SolrQueryConfig queryConfig = new SolrQueryConfig();
>             +
>             +    queryConfig.setCollection("collection1");
>             +
>             +    String expected = "collection1";
>             +    String actual = queryConfig.getCollection();
>             +    assertEquals(expected, actual);
>             +  }
>             +
>             +  @Test
>             +  public void testGetPath() throws Exception {
>             +    SolrQueryConfig queryConfig = new SolrQueryConfig();
>             +
>             +    String expected = "";
>             +    String actual = queryConfig.getPath();
>             +    assertEquals(expected, actual);
>             +  }
>             +
>             +  @Test
>             +  public void testSetPath() throws Exception {
>             +    SolrQueryConfig queryConfig = new SolrQueryConfig();
>             +
>             +    queryConfig.setPath("/select");
>             +
>             +    String expected = "/select";
>             +    String actual = queryConfig.getPath();
>             +    assertEquals(expected, actual);
>             +  }
>             +
>             +  @Test
>             +  public void testGetParams() throws Exception {
>             +    SolrQueryConfig queryConfig = new SolrQueryConfig();
>             +
>             +    List<LinkedHashMap<String, String>> expected = new ArrayList<>();
>             +    List<LinkedHashMap<String, String>> actual = queryConfig.getParams();
>             +    assertEquals(expected, actual);
>             +  }
>             +
>             +  @Test
>             +  public void testSetParams() throws Exception {
>             +    SolrQueryConfig queryConfig = new SolrQueryConfig();
>             +
>             +    LinkedHashMap<String,String> param1 = new LinkedHashMap<>();
>             +    param1.put("q", "*:*");
>             +
>             +    LinkedHashMap<String,String> param2 = new LinkedHashMap<>();
>             +    param2.put("facet", "on");
>             +
>             +    queryConfig.setParams(Arrays.asList(param1, param2));
>             +
>             +    List<LinkedHashMap<String, String>> expected = Arrays.asList(param1, param2);
>             +    List<LinkedHashMap<String, String>> actual = queryConfig.getParams();
>             +    assertEquals(expected, actual);
>             +  }
>             +
>             +  @Test
>             +  public void testGetParamsString() throws Exception {
>             +    SolrQueryConfig queryConfig = new SolrQueryConfig();
>             +
>             +    LinkedHashMap<String,String> param1 = new LinkedHashMap<>();
>             +    param1.put("q", "*:*");
>             +    param1.put("fq", "manu:apple");
>             +
>             +    LinkedHashMap<String,String> param2 = new LinkedHashMap<>();
>             +    param2.put("facet", "on");
>             +
>             +    queryConfig.setParams(Arrays.asList(param1, param2));
>             +
>             +    String expected = "q=*:*&fq=manu:apple&facet=on";
>             +    String actual = queryConfig.getParamsString();
>             +    assertEquals(expected, actual);
>             +  }
>             +}
> 
>             http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/config/SolrScraperConfigTest.java
>             <http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/config/SolrScraperConfigTest.java>
>             ----------------------------------------------------------------------
>             diff --git
>             a/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/config/SolrScraperConfigTest.java
>             b/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/config/SolrScraperConfigTest.java
>             new file mode 100644
>             index 0000000..79d1204
>             --- /dev/null
>             +++
>             b/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/config/SolrScraperConfigTest.java
>             @@ -0,0 +1,86 @@
>             +/*
>             + * 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 <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.prometheus.scraper.config;
>             +
>             +import org.apache.solr.prometheus.collector.config.SolrCollectorConfig;
>             +import org.apache.solr.SolrTestCaseJ4;
>             +import org.junit.Test;
>             +import org.yaml.snakeyaml.Yaml;
>             +
>             +import java.io.FileReader;
>             +import java.util.ArrayList;
>             +import java.util.List;
>             +
>             +/**
>             + * Unit test for SolrScraperConfig.
>             + */
>             +public class SolrScraperConfigTest extends SolrTestCaseJ4 {
>             +  @Test
>             +  public void testScraperConfig() throws Exception {
>             +    String configFile = getFile("conf/config.yml").getAbsolutePath();
>             +
>             +    SolrCollectorConfig config = new Yaml().loadAs(new FileReader(configFile),
>             SolrCollectorConfig.class);
>             +
>             +    SolrScraperConfig scraperConfig = config.getMetrics();
>             +
>             +    assertNotNull(scraperConfig);
>             +  }
>             +
>             +  @Test
>             +  public void testGetJsonQueries() throws Exception {
>             +    String configFile = getFile("conf/config.yml").getAbsolutePath();
>             +
>             +    SolrCollectorConfig collectorConfig = new Yaml().loadAs(new FileReader(configFile),
>             SolrCollectorConfig.class);
>             +
>             +    SolrScraperConfig scraperConfig = collectorConfig.getMetrics();
>             +
>             +    assertNotNull(scraperConfig.getJsonQueries());
>             +  }
>             +
>             +  @Test
>             +  public void testSetJsonQueries() throws Exception {
>             +    List<String> jsonQueries = new ArrayList<>();
>             +
>             +    SolrScraperConfig scraperConfig = new SolrScraperConfig();
>             +
>             +    scraperConfig.setJsonQueries(jsonQueries);
>             +
>             +    assertNotNull(scraperConfig.getJsonQueries());
>             +  }
>             +
>             +  @Test
>             +  public void testGetQueryConfig() throws Exception {
>             +    String configFile = getFile("conf/config.yml").getAbsolutePath();
>             +
>             +    SolrCollectorConfig collectorConfig = new Yaml().loadAs(new FileReader(configFile),
>             SolrCollectorConfig.class);
>             +
>             +    SolrScraperConfig scraperConfig = collectorConfig.getMetrics();
>             +
>             +    assertNotNull(scraperConfig.getQuery());
>             +  }
>             +
>             +  @Test
>             +  public void testSetQueryConfig() throws Exception {
>             +    SolrQueryConfig queryConfig = new SolrQueryConfig();
>             +
>             +    SolrScraperConfig scraperConfig = new SolrScraperConfig();
>             +
>             +    scraperConfig.setQuery(queryConfig);
>             +
>             +    assertNotNull(scraperConfig.getQuery());
>             +  }
>             +}
> 
>             http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/solr-ref-guide/src/images/monitoring-solr-with-prometheus-and-grafana/grafana-solr-dashboard.png
>             <http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/solr-ref-guide/src/images/monitoring-solr-with-prometheus-and-grafana/grafana-solr-dashboard.png>
>             ----------------------------------------------------------------------
>             diff --git
>             a/solr/solr-ref-guide/src/images/monitoring-solr-with-prometheus-and-grafana/grafana-solr-dashboard.png
>             b/solr/solr-ref-guide/src/images/monitoring-solr-with-prometheus-and-grafana/grafana-solr-dashboard.png
>             new file mode 100644
>             index 0000000..69f21a4
>             Binary files /dev/null and
>             b/solr/solr-ref-guide/src/images/monitoring-solr-with-prometheus-and-grafana/grafana-solr-dashboard.png
>             differ
> 
>             http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/solr-ref-guide/src/images/monitoring-solr-with-prometheus-and-grafana/solr-exporter-diagram.png
>             <http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/solr-ref-guide/src/images/monitoring-solr-with-prometheus-and-grafana/solr-exporter-diagram.png>
>             ----------------------------------------------------------------------
>             diff --git
>             a/solr/solr-ref-guide/src/images/monitoring-solr-with-prometheus-and-grafana/solr-exporter-diagram.png
>             b/solr/solr-ref-guide/src/images/monitoring-solr-with-prometheus-and-grafana/solr-exporter-diagram.png
>             new file mode 100644
>             index 0000000..96efece
>             Binary files /dev/null and
>             b/solr/solr-ref-guide/src/images/monitoring-solr-with-prometheus-and-grafana/solr-exporter-diagram.png
>             differ
> 
>             http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/solr-ref-guide/src/monitoring-solr-with-prometheus-and-grafana.adoc
>             <http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/solr-ref-guide/src/monitoring-solr-with-prometheus-and-grafana.adoc>
>             ----------------------------------------------------------------------
>             diff --git a/solr/solr-ref-guide/src/monitoring-solr-with-prometheus-and-grafana.adoc
>             b/solr/solr-ref-guide/src/monitoring-solr-with-prometheus-and-grafana.adoc
>             new file mode 100644
>             index 0000000..1ac55a2
>             --- /dev/null
>             +++ b/solr/solr-ref-guide/src/monitoring-solr-with-prometheus-and-grafana.adoc
>             @@ -0,0 +1,250 @@
>             += Monitoring Solr with Prometheus and Grafana
>             +// 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 <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.
>             +
>             +You can monitor Solr using solr-exporter that exposes Solr's metrics to
>             https://prometheus.io[Prometheus], and visualize metrics using https://grafana.com[Grafana].
>             +
>             +It allows users to monitor not only Solr metrics which come from
>             <<metrics-reporting.adoc#metrics-api,Metrics API>> but also facet counts which come from
>             <<searching.adoc#searching,Searching>>.
>             +
>             +.solr-exporter Diagram
>             +image::images/monitoring-solr-with-prometheus-and-grafana/solr-exporter-diagram.png[image,width=600]
>             +
>             +This feature is experimental status.
>             +
>             +== Running solr-exporter
>             +
>             +You can start solr-exporter by running `./bin/solr-exporter` from the solr-exporter
>             directory.
>             +
>             +[source,plain]
>             +----
>             +$ cd ./contrib/prometheus-exporter
>             +$ ./bin/solr-exporter -p 9983 -b http://localhost:8983/solr -f ./conf/config.yml -n 8
>             +----
>             +
>             +If you are on Windows platform, you can start solr-exporter by running
>             `.\bin\solr-exporter.cmd` instead.
>             +
>             +[source,plain]
>             +----
>             +> cd .\contrib\prometheus
>             +> .\bin\solr-exporter.cmd -p 9983 -b http://localhost:8983/solr -f .\conf\config.yml -n 8
>             +----
>             +
>             +You can also connect to Solr in SolrCloud mode like this.
>             +
>             +[source,plain]
>             +----
>             +$ cd ./contrib/prometheus
>             +$ ./bin/solr-exporter -p 9983 -z localhost:2181/solr -f ./conf/config.yml -n 16
>             +----
>             +
>             +See command help:
>             +
>             +[source,plain]
>             +----
>             +$ ./bin/solr-exporter -h
>             +usage: SolrCollector [-h] [-v] [-p PORT] [-b BASE_URL] [-z ZK_HOST] [-f CONFIG]
>             +                     [-n NUM_THREADS]
>             +
>             +Prometheus exporter for Apache Solr.
>             +
>             +optional arguments:
>             +  -h, --help             show this help message and exit
>             +  -p PORT, --port PORT   solr-exporter listen port
>             +  -b BASE_URL, --baseurl BASE_URL
>             +                         specify Solr base URL when connecting  to Solr in standalone
>             mode (for
>             +                         example 'http://localhost:8983/solr')
>             +  -z ZK_HOST, --zkhost ZK_HOST
>             +                         specify  ZooKeeper  connection  string  when  connecting  to
>               Solr  in
>             +                         SolrCloud mode (for example 'localhost:2181/solr')
>             +  -f CONFIG, --config-file CONFIG
>             +                         specify configuration file
>             +  -n NUM_THREADS, --num-thread NUM_THREADS
>             +                         specify number of threads
>             +----
>             +
>             +The Solr's metrics exposed by solr-exporter can see at the following URL.
>             +
>             +http://localhost:9983/metrics[http://localhost:9983/metrics]
>             <http://localhost:9983/metrics%5Bhttp://localhost:9983/metrics%5D>
>             +
>             +
>             +== Configuration
>             +
>             +The configuration is in `./config/config.yml`. An example with all possible options:
>             +
>             +[source,plain]
>             +----
>             +ping:
>             +  query:
>             +    path: /admin/ping
>             +  jsonQueries:
>             +    - |-
>             +      . as $object | $object |
>             +      (if $object.status == "OK" then 1.0 else 0.0 end) as $value |
>             +      {
>             +        name         : "solr_ping",
>             +        type         : "GAUGE",
>             +        help         : "See following URL:
>             https://lucene.apache.org/solr/guide/ping.html
>             <https://lucene.apache.org/solr/guide/ping.html>",
>             +        label_names  : [],
>             +        label_values : [],
>             +        value        : $value
>             +      }
>             +
>             +metrics:
>             +  query:
>             +    path: /admin/metrics
>             +    params:
>             +      - group: 'all'
>             +      - type: 'all'
>             +      - prefix: ''
>             +      - property: ''
>             +  jsonQueries:
>             +    # solr_metrics_jetty_response_count
>             +    - |-
>             +      .metrics["solr.jetty"] | to_entries | .[] | select(.key |
>             startswith("org.eclipse.jetty.server.handler.DefaultHandler")) | select(.key |
>             endswith("xx-responses")) as $object |
>             +      $object.key | split(".") | last | split("-") | first as $status |
>             +      $object.value.count as $value |
>             +      {
>             +        name         : "solr_metrics_jetty_response_count",
>             +        type         : "gauge",
>             +        help         : "See following URL:
>             https://lucene.apache.org/solr/guide/metrics-reporting.html
>             <https://lucene.apache.org/solr/guide/metrics-reporting.html>",
>             +        label_names  : ["status"],
>             +        label_values : [$status],
>             +        value        : $value
>             +      }
>             +
>             +...
>             +
>             +collections:
>             +  query:
>             +    path: /admin/collections
>             +    params:
>             +      - action: 'CLUSTERSTATUS'
>             +  jsonQueries:
>             +    # solr_collections_cluster_status_live_nodes
>             +    - |-
>             +      .cluster.live_nodes | length as $value|
>             +      {
>             +        name         : "solr_collections_cluster_status_live_nodes",
>             +        type         : "gauge",
>             +        help         : "See following URL:
>             https://lucene.apache.org/solr/guide/collections-api.html#clusterstatus
>             <https://lucene.apache.org/solr/guide/collections-api.html#clusterstatus>",
>             +        label_names  : [],
>             +        label_values : [],
>             +        value        : $value
>             +      }
>             +
>             +...
>             +
>             +queries:
>             +  - query:
>             +      collection: collection1
>             +      path: /select
>             +      params:
>             +        - q: "*:*"
>             +        - start: 0
>             +        - rows: 0
>             +        - json.facet: |-
>             +            {
>             +              category: {
>             +                type: terms,
>             +                field: cat
>             +              }
>             +            }
>             +    jsonQueries:
>             +      # solr_facets_category
>             +      - |-
>             +        .facets.category.buckets[] as $object |
>             +        $object.val as $term |
>             +        $object.count as $value |
>             +        {
>             +          name         : "solr_facets_category",
>             +          type         : "gauge",
>             +          help         : "Category facets",
>             +          label_names  : ["term"],
>             +          label_values : [$term],
>             +          value        : $value
>             +        }
>             +----
>             +
>             +|===
>             +|Name|Description
>             +
>             +|ping|Scrape <<ping.adoc#ping,Ping>> response.
>             +|metrics|Scrape <<metrics-reporting.adoc#metrics-api,Metrics API>> response.
>             +|collections|Scrape <<collections-api.adoc#collections-api,Collections API>> response.
>             +|queries|Scrape <<searching.adoc#searching,Search API>> response.
>             +|*.query|Query parameter for each features. You can specify `collection`, `core`,
>             `path`, and `params`.
>             +|*.jsonQueries|JSON Query that is jq syntax. For more details, see
>             https://stedolan.github.io/jq/manual/[https://stedolan.github.io/jq/manual/]
>             <https://stedolan.github.io/jq/manual/%5Bhttps://stedolan.github.io/jq/manual/%5D>.
>             +|===
>             +
>             +jq query has to output JSON in the following format.
>             +
>             +[source,json]
>             +----
>             +{
>             +  name         : "solr_ping",
>             +  type         : "GAUGE",
>             +  help         : "See following URL: https://lucene.apache.org/solr/guide/ping.html
>             <https://lucene.apache.org/solr/guide/ping.html>",
>             +  label_names  : ["base_url","core"],
>             +  label_values : ["http://localhost:8983/solr","collection1"],
>             +  value        : 1.0
>             +}
>             +----
>             +
>             +It will be converted to the following exposition format.
>             +
>             +[source,plain]
>             +----
>             +# TYPE solr_ping gauge
>             +# HELP solr_ping See following URL: https://lucene.apache.org/solr/guide/ping.html
>             <https://lucene.apache.org/solr/guide/ping.html>
>             +solr_ping{base_url="http://localhost:8983/solr
>             <http://localhost:8983/solr>",core="collection1"} 1.0
>             +----
>             +
>             +|===
>             +|Name|Description
>             +
>             +|name|The metric name to set. For more details, see
>             https://prometheus.io/docs/practices/naming/[https://prometheus.io/docs/practices/naming/]
>             <https://prometheus.io/docs/practices/naming/%5Bhttps://prometheus.io/docs/practices/naming/%5D>.
>             +|type|The type of the metric, can be `COUNTER`, `GAUGE`, `SUMMARY`, `HISTOGRAM` or
>             `UNTYPED`. For more detauils, see
>             https://prometheus.io/docs/concepts/metric_types/[https://prometheus.io/docs/concepts/metric_types/]
>             <https://prometheus.io/docs/concepts/metric_types/%5Bhttps://prometheus.io/docs/concepts/metric_types/%5D>.
>             +|help|Help text for the metric.
>             +|label_names|Label names for the metric. For more details, see
>             https://prometheus.io/docs/practices/naming/[https://prometheus.io/docs/practices/naming/]
>             <https://prometheus.io/docs/practices/naming/%5Bhttps://prometheus.io/docs/practices/naming/%5D>.
>             +|label_values|Label values for the metric. For more details, see
>             https://prometheus.io/docs/practices/naming/[https://prometheus.io/docs/practices/naming/]
>             <https://prometheus.io/docs/practices/naming/%5Bhttps://prometheus.io/docs/practices/naming/%5D>.
>             +|value|Value for the metric. Value must be set to Double type.
>             +|===
>             +
>             +
>             +== Prometheus Settings
>             +
>             +You need to specify the solr-exporter listen address into `scrape_configs` in
>             `prometheus.yml`. See following example:
>             +
>             +[source,plain]
>             +----
>             +scrape_configs:
>             +  - job_name: 'solr'
>             +    static_configs:
>             +      - targets: ['localhost:9983']
>             +----
>             +
>             +When you apply the above settings to prometheus, it will start to pull Solr's metrics
>             from solr-exporter.
>             +
>             +
>             +== Grafana Dashboard
>             +
>             +A Grafana sample dashboard is provided at the following JSON file.
>             +
>             +`./conf/grafana-solr-dashboard.json`
>             +
>             +.Grafana Dashboard
>             +image::images/monitoring-solr-with-prometheus-and-grafana/grafana-solr-dashboard.png[image,width=800]
> 
>             http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/solr-ref-guide/src/monitoring-solr.adoc
>             <http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/solr-ref-guide/src/monitoring-solr.adoc>
>             ----------------------------------------------------------------------
>             diff --git a/solr/solr-ref-guide/src/monitoring-solr.adoc
>             b/solr/solr-ref-guide/src/monitoring-solr.adoc
>             index 0576e53..2fb7077 100644
>             --- a/solr/solr-ref-guide/src/monitoring-solr.adoc
>             +++ b/solr/solr-ref-guide/src/monitoring-solr.adoc
>             @@ -1,5 +1,5 @@
>             = Monitoring Solr
>             -:page-children: metrics-reporting, mbean-request-handler, configuring-logging,
>             using-jmx-with-solr, performance-statistics-reference
>             +:page-children: metrics-reporting, mbean-request-handler, configuring-logging,
>             using-jmx-with-solr, monitoring-solr-with-prometheus-and-grafana,
>             performance-statistics-reference
>             // 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
>             @@ -30,6 +30,8 @@ Common administrative tasks include:
> 
>             <<using-jmx-with-solr.adoc#using-jmx-with-solr,Using JMX with Solr>>: Describes how to
>             use Java Management Extensions with Solr.
> 
>             +<<monitoring-solr-with-prometheus-and-grafana.adoc#monitoring-solr-with-prometheus-and-grafana,Monitoring
>             Solr with Prometheus and Grafana>>: Describes how to monitor Solr with Prometheus and
>             Grafana.
>             +
>             <<performance-statistics-reference.adoc#performance-statistics-reference,Performance
>             Statistics Reference>>: Additional information on statistics returned from JMX.
> 
> 
> 
> 
> 
>     ---------------------------------------------------------------------
>     To unsubscribe, e-mail: dev-unsubscribe@lucene.apache.org <ma...@lucene.apache.org>
>     For additional commands, e-mail: dev-help@lucene.apache.org <ma...@lucene.apache.org>
> 
> 

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@lucene.apache.org
For additional commands, e-mail: dev-help@lucene.apache.org


Re: [1/7] lucene-solr:master: SOLR-11795: Add Solr metrics exporter for Prometheus

Posted by Cassandra Targett <ca...@gmail.com>.
Ref Guide builds are also failing due to duplicate section headings on two
pages.

https://builds.apache.org/job/Solr-reference-guide-master/5499/console:

build-site:
     [java] ID occurs multiple times: configuration
     [java]  ...
file:/home/jenkins/jenkins-slave/workspace/Solr-reference-guide-master/solr/build/solr-ref-guide/html-site/monitoring-solr-with-prometheus-and-grafana.html
     [java]  ...
file:/home/jenkins/jenkins-slave/workspace/Solr-reference-guide-master/solr/build/solr-ref-guide/html-site/parallel-sql-interface.html


This will cause links between sections of the PDF to go to the wrong place,
so each section must be unique. I'd suggest in this case possibly changing
the new page section heading "Configuration" to "solr-exporter
Configuration" or something similar.


On Tue, Feb 20, 2018 at 7:34 AM, Koji Sekiguchi <koji.sekiguchi@rondhuit.com
> wrote:

> I'm sorry. Let me check...
>
>
> On 2018/02/20 20:50, Andrzej Białecki wrote:
>
>> Builds on jenkins are failing due to precommit failures in this code...
>>
>> On 20 Feb 2018, at 09:47, koji@apache.org <ma...@apache.org> wrote:
>>>
>>> Repository: lucene-solr
>>> Updated Branches:
>>>  refs/heads/master dfc0fe86e -> 4bfcbc5c6
>>>
>>>
>>> http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfc
>>> bc5c/solr/contrib/prometheus-exporter/src/test/org/apache/
>>> solr/prometheus/scraper/config/SolrQueryConfigTest.java
>>> ----------------------------------------------------------------------
>>> diff --git a/solr/contrib/prometheus-exporter/src/test/org/apache/solr/
>>> prometheus/scraper/config/SolrQueryConfigTest.java
>>> b/solr/contrib/prometheus-exporter/src/test/org/apache/solr/
>>> prometheus/scraper/config/SolrQueryConfigTest.java
>>> new file mode 100644
>>> index 0000000..c62d354
>>> --- /dev/null
>>> +++ b/solr/contrib/prometheus-exporter/src/test/org/apache/solr/
>>> prometheus/scraper/config/SolrQueryConfigTest.java
>>> @@ -0,0 +1,121 @@
>>> +/*
>>> + * 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.prometheus.scraper.config;
>>> +
>>> +import org.apache.solr.SolrTestCaseJ4;
>>> +import org.junit.Test;
>>> +
>>> +import java.util.ArrayList;
>>> +import java.util.Arrays;
>>> +import java.util.LinkedHashMap;
>>> +import java.util.List;
>>> +
>>> +/**
>>> + * Unit test for SolrQueryConfig.
>>> + */
>>> +public class SolrQueryConfigTest extends SolrTestCaseJ4 {
>>> +  @Test
>>> +  public void testQueryConfig() throws Exception {
>>> +    SolrQueryConfig queryConfig = new SolrQueryConfig();
>>> +
>>> +    assertNotNull(queryConfig);
>>> +  }
>>> +
>>> +  @Test
>>> +  public void testGetCollection() throws Exception {
>>> +    SolrQueryConfig queryConfig = new SolrQueryConfig();
>>> +
>>> +    String expected = "";
>>> +    String actual = queryConfig.getCollection();
>>> +    assertEquals(expected, actual);
>>> +  }
>>> +
>>> +  @Test
>>> +  public void testSetCollection() throws Exception {
>>> +    SolrQueryConfig queryConfig = new SolrQueryConfig();
>>> +
>>> +    queryConfig.setCollection("collection1");
>>> +
>>> +    String expected = "collection1";
>>> +    String actual = queryConfig.getCollection();
>>> +    assertEquals(expected, actual);
>>> +  }
>>> +
>>> +  @Test
>>> +  public void testGetPath() throws Exception {
>>> +    SolrQueryConfig queryConfig = new SolrQueryConfig();
>>> +
>>> +    String expected = "";
>>> +    String actual = queryConfig.getPath();
>>> +    assertEquals(expected, actual);
>>> +  }
>>> +
>>> +  @Test
>>> +  public void testSetPath() throws Exception {
>>> +    SolrQueryConfig queryConfig = new SolrQueryConfig();
>>> +
>>> +    queryConfig.setPath("/select");
>>> +
>>> +    String expected = "/select";
>>> +    String actual = queryConfig.getPath();
>>> +    assertEquals(expected, actual);
>>> +  }
>>> +
>>> +  @Test
>>> +  public void testGetParams() throws Exception {
>>> +    SolrQueryConfig queryConfig = new SolrQueryConfig();
>>> +
>>> +    List<LinkedHashMap<String, String>> expected = new ArrayList<>();
>>> +    List<LinkedHashMap<String, String>> actual =
>>> queryConfig.getParams();
>>> +    assertEquals(expected, actual);
>>> +  }
>>> +
>>> +  @Test
>>> +  public void testSetParams() throws Exception {
>>> +    SolrQueryConfig queryConfig = new SolrQueryConfig();
>>> +
>>> +    LinkedHashMap<String,String> param1 = new LinkedHashMap<>();
>>> +    param1.put("q", "*:*");
>>> +
>>> +    LinkedHashMap<String,String> param2 = new LinkedHashMap<>();
>>> +    param2.put("facet", "on");
>>> +
>>> +    queryConfig.setParams(Arrays.asList(param1, param2));
>>> +
>>> +    List<LinkedHashMap<String, String>> expected =
>>> Arrays.asList(param1, param2);
>>> +    List<LinkedHashMap<String, String>> actual =
>>> queryConfig.getParams();
>>> +    assertEquals(expected, actual);
>>> +  }
>>> +
>>> +  @Test
>>> +  public void testGetParamsString() throws Exception {
>>> +    SolrQueryConfig queryConfig = new SolrQueryConfig();
>>> +
>>> +    LinkedHashMap<String,String> param1 = new LinkedHashMap<>();
>>> +    param1.put("q", "*:*");
>>> +    param1.put("fq", "manu:apple");
>>> +
>>> +    LinkedHashMap<String,String> param2 = new LinkedHashMap<>();
>>> +    param2.put("facet", "on");
>>> +
>>> +    queryConfig.setParams(Arrays.asList(param1, param2));
>>> +
>>> +    String expected = "q=*:*&fq=manu:apple&facet=on";
>>> +    String actual = queryConfig.getParamsString();
>>> +    assertEquals(expected, actual);
>>> +  }
>>> +}
>>>
>>> http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfc
>>> bc5c/solr/contrib/prometheus-exporter/src/test/org/apache/
>>> solr/prometheus/scraper/config/SolrScraperConfigTest.java
>>> ----------------------------------------------------------------------
>>> diff --git a/solr/contrib/prometheus-exporter/src/test/org/apache/solr/
>>> prometheus/scraper/config/SolrScraperConfigTest.java
>>> b/solr/contrib/prometheus-exporter/src/test/org/apache/solr/
>>> prometheus/scraper/config/SolrScraperConfigTest.java
>>> new file mode 100644
>>> index 0000000..79d1204
>>> --- /dev/null
>>> +++ b/solr/contrib/prometheus-exporter/src/test/org/apache/solr/
>>> prometheus/scraper/config/SolrScraperConfigTest.java
>>> @@ -0,0 +1,86 @@
>>> +/*
>>> + * 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.prometheus.scraper.config;
>>> +
>>> +import org.apache.solr.prometheus.collector.config.SolrCollectorConfig;
>>> +import org.apache.solr.SolrTestCaseJ4;
>>> +import org.junit.Test;
>>> +import org.yaml.snakeyaml.Yaml;
>>> +
>>> +import java.io.FileReader;
>>> +import java.util.ArrayList;
>>> +import java.util.List;
>>> +
>>> +/**
>>> + * Unit test for SolrScraperConfig.
>>> + */
>>> +public class SolrScraperConfigTest extends SolrTestCaseJ4 {
>>> +  @Test
>>> +  public void testScraperConfig() throws Exception {
>>> +    String configFile = getFile("conf/config.yml").getAbsolutePath();
>>> +
>>> +    SolrCollectorConfig config = new Yaml().loadAs(new
>>> FileReader(configFile), SolrCollectorConfig.class);
>>> +
>>> +    SolrScraperConfig scraperConfig = config.getMetrics();
>>> +
>>> +    assertNotNull(scraperConfig);
>>> +  }
>>> +
>>> +  @Test
>>> +  public void testGetJsonQueries() throws Exception {
>>> +    String configFile = getFile("conf/config.yml").getAbsolutePath();
>>> +
>>> +    SolrCollectorConfig collectorConfig = new Yaml().loadAs(new
>>> FileReader(configFile), SolrCollectorConfig.class);
>>> +
>>> +    SolrScraperConfig scraperConfig = collectorConfig.getMetrics();
>>> +
>>> +    assertNotNull(scraperConfig.getJsonQueries());
>>> +  }
>>> +
>>> +  @Test
>>> +  public void testSetJsonQueries() throws Exception {
>>> +    List<String> jsonQueries = new ArrayList<>();
>>> +
>>> +    SolrScraperConfig scraperConfig = new SolrScraperConfig();
>>> +
>>> +    scraperConfig.setJsonQueries(jsonQueries);
>>> +
>>> +    assertNotNull(scraperConfig.getJsonQueries());
>>> +  }
>>> +
>>> +  @Test
>>> +  public void testGetQueryConfig() throws Exception {
>>> +    String configFile = getFile("conf/config.yml").getAbsolutePath();
>>> +
>>> +    SolrCollectorConfig collectorConfig = new Yaml().loadAs(new
>>> FileReader(configFile), SolrCollectorConfig.class);
>>> +
>>> +    SolrScraperConfig scraperConfig = collectorConfig.getMetrics();
>>> +
>>> +    assertNotNull(scraperConfig.getQuery());
>>> +  }
>>> +
>>> +  @Test
>>> +  public void testSetQueryConfig() throws Exception {
>>> +    SolrQueryConfig queryConfig = new SolrQueryConfig();
>>> +
>>> +    SolrScraperConfig scraperConfig = new SolrScraperConfig();
>>> +
>>> +    scraperConfig.setQuery(queryConfig);
>>> +
>>> +    assertNotNull(scraperConfig.getQuery());
>>> +  }
>>> +}
>>>
>>> http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfc
>>> bc5c/solr/solr-ref-guide/src/images/monitoring-solr-with-
>>> prometheus-and-grafana/grafana-solr-dashboard.png
>>> ----------------------------------------------------------------------
>>> diff --git a/solr/solr-ref-guide/src/images/monitoring-solr-with-promet
>>> heus-and-grafana/grafana-solr-dashboard.png
>>> b/solr/solr-ref-guide/src/images/monitoring-solr-with-promet
>>> heus-and-grafana/grafana-solr-dashboard.png
>>> new file mode 100644
>>> index 0000000..69f21a4
>>> Binary files /dev/null and b/solr/solr-ref-guide/src/imag
>>> es/monitoring-solr-with-prometheus-and-grafana/grafana-solr-dashboard.png
>>> differ
>>>
>>> http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfc
>>> bc5c/solr/solr-ref-guide/src/images/monitoring-solr-with-
>>> prometheus-and-grafana/solr-exporter-diagram.png
>>> ----------------------------------------------------------------------
>>> diff --git a/solr/solr-ref-guide/src/images/monitoring-solr-with-promet
>>> heus-and-grafana/solr-exporter-diagram.png
>>> b/solr/solr-ref-guide/src/images/monitoring-solr-with-promet
>>> heus-and-grafana/solr-exporter-diagram.png
>>> new file mode 100644
>>> index 0000000..96efece
>>> Binary files /dev/null and b/solr/solr-ref-guide/src/imag
>>> es/monitoring-solr-with-prometheus-and-grafana/solr-exporter-diagram.png
>>> differ
>>>
>>> http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfc
>>> bc5c/solr/solr-ref-guide/src/monitoring-solr-with-prometheu
>>> s-and-grafana.adoc
>>> ----------------------------------------------------------------------
>>> diff --git a/solr/solr-ref-guide/src/monitoring-solr-with-prometheus-and-grafana.adoc
>>> b/solr/solr-ref-guide/src/monitoring-solr-with-prometheus-
>>> and-grafana.adoc
>>> new file mode 100644
>>> index 0000000..1ac55a2
>>> --- /dev/null
>>> +++ b/solr/solr-ref-guide/src/monitoring-solr-with-prometheus-
>>> and-grafana.adoc
>>> @@ -0,0 +1,250 @@
>>> += Monitoring Solr with Prometheus and Grafana
>>> +// 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.
>>> +
>>> +You can monitor Solr using solr-exporter that exposes Solr's metrics to
>>> https://prometheus.io[Prometheus], and visualize metrics using
>>> https://grafana.com[Grafana].
>>> +
>>> +It allows users to monitor not only Solr metrics which come from
>>> <<metrics-reporting.adoc#metrics-api,Metrics API>> but also facet
>>> counts which come from <<searching.adoc#searching,Searching>>.
>>> +
>>> +.solr-exporter Diagram
>>> +image::images/monitoring-solr-with-prometheus-and-grafana/
>>> solr-exporter-diagram.png[image,width=600]
>>> +
>>> +This feature is experimental status.
>>> +
>>> +== Running solr-exporter
>>> +
>>> +You can start solr-exporter by running `./bin/solr-exporter` from the
>>> solr-exporter directory.
>>> +
>>> +[source,plain]
>>> +----
>>> +$ cd ./contrib/prometheus-exporter
>>> +$ ./bin/solr-exporter -p 9983 -b http://localhost:8983/solr -f
>>> ./conf/config.yml -n 8
>>> +----
>>> +
>>> +If you are on Windows platform, you can start solr-exporter by running
>>> `.\bin\solr-exporter.cmd` instead.
>>> +
>>> +[source,plain]
>>> +----
>>> +> cd .\contrib\prometheus
>>> +> .\bin\solr-exporter.cmd -p 9983 -b http://localhost:8983/solr -f
>>> .\conf\config.yml -n 8
>>> +----
>>> +
>>> +You can also connect to Solr in SolrCloud mode like this.
>>> +
>>> +[source,plain]
>>> +----
>>> +$ cd ./contrib/prometheus
>>> +$ ./bin/solr-exporter -p 9983 -z localhost:2181/solr -f
>>> ./conf/config.yml -n 16
>>> +----
>>> +
>>> +See command help:
>>> +
>>> +[source,plain]
>>> +----
>>> +$ ./bin/solr-exporter -h
>>> +usage: SolrCollector [-h] [-v] [-p PORT] [-b BASE_URL] [-z ZK_HOST] [-f
>>> CONFIG]
>>> +                     [-n NUM_THREADS]
>>> +
>>> +Prometheus exporter for Apache Solr.
>>> +
>>> +optional arguments:
>>> +  -h, --help             show this help message and exit
>>> +  -p PORT, --port PORT   solr-exporter listen port
>>> +  -b BASE_URL, --baseurl BASE_URL
>>> +                         specify Solr base URL when connecting  to
>>> Solr in standalone mode (for
>>> +                         example 'http://localhost:8983/solr')
>>> +  -z ZK_HOST, --zkhost ZK_HOST
>>> +                         specify  ZooKeeper  connection  string  when
>>>  connecting  to  Solr  in
>>> +                         SolrCloud mode (for example
>>> 'localhost:2181/solr')
>>> +  -f CONFIG, --config-file CONFIG
>>> +                         specify configuration file
>>> +  -n NUM_THREADS, --num-thread NUM_THREADS
>>> +                         specify number of threads
>>> +----
>>> +
>>> +The Solr's metrics exposed by solr-exporter can see at the following
>>> URL.
>>> +
>>> +http://localhost:9983/metrics[http://localhost:9983/metrics]
>>> +
>>> +
>>> +== Configuration
>>> +
>>> +The configuration is in `./config/config.yml`. An example with all
>>> possible options:
>>> +
>>> +[source,plain]
>>> +----
>>> +ping:
>>> +  query:
>>> +    path: /admin/ping
>>> +  jsonQueries:
>>> +    - |-
>>> +      . as $object | $object |
>>> +      (if $object.status == "OK" then 1.0 else 0.0 end) as $value |
>>> +      {
>>> +        name         : "solr_ping",
>>> +        type         : "GAUGE",
>>> +        help         : "See following URL:
>>> https://lucene.apache.org/solr/guide/ping.html",
>>> +        label_names  : [],
>>> +        label_values : [],
>>> +        value        : $value
>>> +      }
>>> +
>>> +metrics:
>>> +  query:
>>> +    path: /admin/metrics
>>> +    params:
>>> +      - group: 'all'
>>> +      - type: 'all'
>>> +      - prefix: ''
>>> +      - property: ''
>>> +  jsonQueries:
>>> +    # solr_metrics_jetty_response_count
>>> +    - |-
>>> +      .metrics["solr.jetty"] | to_entries | .[] | select(.key |
>>> startswith("org.eclipse.jetty.server.handler.DefaultHandler")) |
>>> select(.key | endswith("xx-responses")) as $object |
>>> +      $object.key | split(".") | last | split("-") | first as $status |
>>> +      $object.value.count as $value |
>>> +      {
>>> +        name         : "solr_metrics_jetty_response_count",
>>> +        type         : "gauge",
>>> +        help         : "See following URL:
>>> https://lucene.apache.org/solr/guide/metrics-reporting.html",
>>> +        label_names  : ["status"],
>>> +        label_values : [$status],
>>> +        value        : $value
>>> +      }
>>> +
>>> +...
>>> +
>>> +collections:
>>> +  query:
>>> +    path: /admin/collections
>>> +    params:
>>> +      - action: 'CLUSTERSTATUS'
>>> +  jsonQueries:
>>> +    # solr_collections_cluster_status_live_nodes
>>> +    - |-
>>> +      .cluster.live_nodes | length as $value|
>>> +      {
>>> +        name         : "solr_collections_cluster_status_live_nodes",
>>> +        type         : "gauge",
>>> +        help         : "See following URL:
>>> https://lucene.apache.org/solr/guide/collections-api.html#clusterstatus
>>> ",
>>> +        label_names  : [],
>>> +        label_values : [],
>>> +        value        : $value
>>> +      }
>>> +
>>> +...
>>> +
>>> +queries:
>>> +  - query:
>>> +      collection: collection1
>>> +      path: /select
>>> +      params:
>>> +        - q: "*:*"
>>> +        - start: 0
>>> +        - rows: 0
>>> +        - json.facet: |-
>>> +            {
>>> +              category: {
>>> +                type: terms,
>>> +                field: cat
>>> +              }
>>> +            }
>>> +    jsonQueries:
>>> +      # solr_facets_category
>>> +      - |-
>>> +        .facets.category.buckets[] as $object |
>>> +        $object.val as $term |
>>> +        $object.count as $value |
>>> +        {
>>> +          name         : "solr_facets_category",
>>> +          type         : "gauge",
>>> +          help         : "Category facets",
>>> +          label_names  : ["term"],
>>> +          label_values : [$term],
>>> +          value        : $value
>>> +        }
>>> +----
>>> +
>>> +|===
>>> +|Name|Description
>>> +
>>> +|ping|Scrape <<ping.adoc#ping,Ping>> response.
>>> +|metrics|Scrape <<metrics-reporting.adoc#metrics-api,Metrics API>>
>>> response.
>>> +|collections|Scrape <<collections-api.adoc#collections-api,Collections
>>> API>> response.
>>> +|queries|Scrape <<searching.adoc#searching,Search API>> response.
>>> +|*.query|Query parameter for each features. You can specify
>>> `collection`, `core`, `path`, and `params`.
>>> +|*.jsonQueries|JSON Query that is jq syntax. For more details, see
>>> https://stedolan.github.io/jq/manual/[https://stedolan.githu
>>> b.io/jq/manual/].
>>> +|===
>>> +
>>> +jq query has to output JSON in the following format.
>>> +
>>> +[source,json]
>>> +----
>>> +{
>>> +  name         : "solr_ping",
>>> +  type         : "GAUGE",
>>> +  help         : "See following URL: https://lucene.apache.org/solr
>>> /guide/ping.html",
>>> +  label_names  : ["base_url","core"],
>>> +  label_values : ["http://localhost:8983/solr","collection1"],
>>> +  value        : 1.0
>>> +}
>>> +----
>>> +
>>> +It will be converted to the following exposition format.
>>> +
>>> +[source,plain]
>>> +----
>>> +# TYPE solr_ping gauge
>>> +# HELP solr_ping See following URL: https://lucene.apache.org/solr
>>> /guide/ping.html
>>> +solr_ping{base_url="http://localhost:8983/solr",core="collection1"} 1.0
>>> +----
>>> +
>>> +|===
>>> +|Name|Description
>>> +
>>> +|name|The metric name to set. For more details, see
>>> https://prometheus.io/docs/practices/naming/[https://prometh
>>> eus.io/docs/practices/naming/].
>>> +|type|The type of the metric, can be `COUNTER`, `GAUGE`, `SUMMARY`,
>>> `HISTOGRAM` or `UNTYPED`. For more detauils, see
>>> https://prometheus.io/docs/concepts/metric_types/[https://
>>> prometheus.io/docs/concepts/metric_types/].
>>> +|help|Help text for the metric.
>>> +|label_names|Label names for the metric. For more details, see
>>> https://prometheus.io/docs/practices/naming/[https://prometh
>>> eus.io/docs/practices/naming/].
>>> +|label_values|Label values for the metric. For more details, see
>>> https://prometheus.io/docs/practices/naming/[https://prometh
>>> eus.io/docs/practices/naming/].
>>> +|value|Value for the metric. Value must be set to Double type.
>>> +|===
>>> +
>>> +
>>> +== Prometheus Settings
>>> +
>>> +You need to specify the solr-exporter listen address into
>>> `scrape_configs` in `prometheus.yml`. See following example:
>>> +
>>> +[source,plain]
>>> +----
>>> +scrape_configs:
>>> +  - job_name: 'solr'
>>> +    static_configs:
>>> +      - targets: ['localhost:9983']
>>> +----
>>> +
>>> +When you apply the above settings to prometheus, it will start to pull
>>> Solr's metrics from solr-exporter.
>>> +
>>> +
>>> +== Grafana Dashboard
>>> +
>>> +A Grafana sample dashboard is provided at the following JSON file.
>>> +
>>> +`./conf/grafana-solr-dashboard.json`
>>> +
>>> +.Grafana Dashboard
>>> +image::images/monitoring-solr-with-prometheus-and-grafana/
>>> grafana-solr-dashboard.png[image,width=800]
>>>
>>> http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfc
>>> bc5c/solr/solr-ref-guide/src/monitoring-solr.adoc
>>> ----------------------------------------------------------------------
>>> diff --git a/solr/solr-ref-guide/src/monitoring-solr.adoc
>>> b/solr/solr-ref-guide/src/monitoring-solr.adoc
>>> index 0576e53..2fb7077 100644
>>> --- a/solr/solr-ref-guide/src/monitoring-solr.adoc
>>> +++ b/solr/solr-ref-guide/src/monitoring-solr.adoc
>>> @@ -1,5 +1,5 @@
>>> = Monitoring Solr
>>> -:page-children: metrics-reporting, mbean-request-handler,
>>> configuring-logging, using-jmx-with-solr, performance-statistics-referen
>>> ce
>>> +:page-children: metrics-reporting, mbean-request-handler,
>>> configuring-logging, using-jmx-with-solr, monitoring-solr-with-prometheus-and-grafana,
>>> performance-statistics-reference
>>> // 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
>>> @@ -30,6 +30,8 @@ Common administrative tasks include:
>>>
>>> <<using-jmx-with-solr.adoc#using-jmx-with-solr,Using JMX with Solr>>:
>>> Describes how to use Java Management Extensions with Solr.
>>>
>>> +<<monitoring-solr-with-prometheus-and-grafana.adoc#monitori
>>> ng-solr-with-prometheus-and-grafana,Monitoring Solr with Prometheus and
>>> Grafana>>: Describes how to monitor Solr with Prometheus and Grafana.
>>> +
>>> <<performance-statistics-reference.adoc#performance-statistics-reference,Performance
>>> Statistics Reference>>: Additional information on statistics returned from
>>> JMX.
>>>
>>>
>>>
>>>
>>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@lucene.apache.org
> For additional commands, e-mail: dev-help@lucene.apache.org
>
>

Re: [1/7] lucene-solr:master: SOLR-11795: Add Solr metrics exporter for Prometheus

Posted by Koji Sekiguchi <ko...@rondhuit.com>.
I'm sorry. Let me check...


On 2018/02/20 20:50, Andrzej Białecki wrote:
> Builds on jenkins are failing due to precommit failures in this code...
> 
>> On 20 Feb 2018, at 09:47, koji@apache.org <ma...@apache.org> wrote:
>>
>> Repository: lucene-solr
>> Updated Branches:
>>  refs/heads/master dfc0fe86e -> 4bfcbc5c6
>>
>>
>> http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/config/SolrQueryConfigTest.java
>> ----------------------------------------------------------------------
>> diff --git 
>> a/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/config/SolrQueryConfigTest.java 
>> b/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/config/SolrQueryConfigTest.java
>> new file mode 100644
>> index 0000000..c62d354
>> --- /dev/null
>> +++ 
>> b/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/config/SolrQueryConfigTest.java
>> @@ -0,0 +1,121 @@
>> +/*
>> + * 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.prometheus.scraper.config;
>> +
>> +import org.apache.solr.SolrTestCaseJ4;
>> +import org.junit.Test;
>> +
>> +import java.util.ArrayList;
>> +import java.util.Arrays;
>> +import java.util.LinkedHashMap;
>> +import java.util.List;
>> +
>> +/**
>> + * Unit test for SolrQueryConfig.
>> + */
>> +public class SolrQueryConfigTest extends SolrTestCaseJ4 {
>> +  @Test
>> +  public void testQueryConfig() throws Exception {
>> +    SolrQueryConfig queryConfig = new SolrQueryConfig();
>> +
>> +    assertNotNull(queryConfig);
>> +  }
>> +
>> +  @Test
>> +  public void testGetCollection() throws Exception {
>> +    SolrQueryConfig queryConfig = new SolrQueryConfig();
>> +
>> +    String expected = "";
>> +    String actual = queryConfig.getCollection();
>> +    assertEquals(expected, actual);
>> +  }
>> +
>> +  @Test
>> +  public void testSetCollection() throws Exception {
>> +    SolrQueryConfig queryConfig = new SolrQueryConfig();
>> +
>> +    queryConfig.setCollection("collection1");
>> +
>> +    String expected = "collection1";
>> +    String actual = queryConfig.getCollection();
>> +    assertEquals(expected, actual);
>> +  }
>> +
>> +  @Test
>> +  public void testGetPath() throws Exception {
>> +    SolrQueryConfig queryConfig = new SolrQueryConfig();
>> +
>> +    String expected = "";
>> +    String actual = queryConfig.getPath();
>> +    assertEquals(expected, actual);
>> +  }
>> +
>> +  @Test
>> +  public void testSetPath() throws Exception {
>> +    SolrQueryConfig queryConfig = new SolrQueryConfig();
>> +
>> +    queryConfig.setPath("/select");
>> +
>> +    String expected = "/select";
>> +    String actual = queryConfig.getPath();
>> +    assertEquals(expected, actual);
>> +  }
>> +
>> +  @Test
>> +  public void testGetParams() throws Exception {
>> +    SolrQueryConfig queryConfig = new SolrQueryConfig();
>> +
>> +    List<LinkedHashMap<String, String>> expected = new ArrayList<>();
>> +    List<LinkedHashMap<String, String>> actual = queryConfig.getParams();
>> +    assertEquals(expected, actual);
>> +  }
>> +
>> +  @Test
>> +  public void testSetParams() throws Exception {
>> +    SolrQueryConfig queryConfig = new SolrQueryConfig();
>> +
>> +    LinkedHashMap<String,String> param1 = new LinkedHashMap<>();
>> +    param1.put("q", "*:*");
>> +
>> +    LinkedHashMap<String,String> param2 = new LinkedHashMap<>();
>> +    param2.put("facet", "on");
>> +
>> +    queryConfig.setParams(Arrays.asList(param1, param2));
>> +
>> +    List<LinkedHashMap<String, String>> expected = Arrays.asList(param1, param2);
>> +    List<LinkedHashMap<String, String>> actual = queryConfig.getParams();
>> +    assertEquals(expected, actual);
>> +  }
>> +
>> +  @Test
>> +  public void testGetParamsString() throws Exception {
>> +    SolrQueryConfig queryConfig = new SolrQueryConfig();
>> +
>> +    LinkedHashMap<String,String> param1 = new LinkedHashMap<>();
>> +    param1.put("q", "*:*");
>> +    param1.put("fq", "manu:apple");
>> +
>> +    LinkedHashMap<String,String> param2 = new LinkedHashMap<>();
>> +    param2.put("facet", "on");
>> +
>> +    queryConfig.setParams(Arrays.asList(param1, param2));
>> +
>> +    String expected = "q=*:*&fq=manu:apple&facet=on";
>> +    String actual = queryConfig.getParamsString();
>> +    assertEquals(expected, actual);
>> +  }
>> +}
>>
>> http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/config/SolrScraperConfigTest.java
>> ----------------------------------------------------------------------
>> diff --git 
>> a/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/config/SolrScraperConfigTest.java 
>> b/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/config/SolrScraperConfigTest.java
>> new file mode 100644
>> index 0000000..79d1204
>> --- /dev/null
>> +++ 
>> b/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/config/SolrScraperConfigTest.java
>> @@ -0,0 +1,86 @@
>> +/*
>> + * 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.prometheus.scraper.config;
>> +
>> +import org.apache.solr.prometheus.collector.config.SolrCollectorConfig;
>> +import org.apache.solr.SolrTestCaseJ4;
>> +import org.junit.Test;
>> +import org.yaml.snakeyaml.Yaml;
>> +
>> +import java.io.FileReader;
>> +import java.util.ArrayList;
>> +import java.util.List;
>> +
>> +/**
>> + * Unit test for SolrScraperConfig.
>> + */
>> +public class SolrScraperConfigTest extends SolrTestCaseJ4 {
>> +  @Test
>> +  public void testScraperConfig() throws Exception {
>> +    String configFile = getFile("conf/config.yml").getAbsolutePath();
>> +
>> +    SolrCollectorConfig config = new Yaml().loadAs(new FileReader(configFile), 
>> SolrCollectorConfig.class);
>> +
>> +    SolrScraperConfig scraperConfig = config.getMetrics();
>> +
>> +    assertNotNull(scraperConfig);
>> +  }
>> +
>> +  @Test
>> +  public void testGetJsonQueries() throws Exception {
>> +    String configFile = getFile("conf/config.yml").getAbsolutePath();
>> +
>> +    SolrCollectorConfig collectorConfig = new Yaml().loadAs(new FileReader(configFile), 
>> SolrCollectorConfig.class);
>> +
>> +    SolrScraperConfig scraperConfig = collectorConfig.getMetrics();
>> +
>> +    assertNotNull(scraperConfig.getJsonQueries());
>> +  }
>> +
>> +  @Test
>> +  public void testSetJsonQueries() throws Exception {
>> +    List<String> jsonQueries = new ArrayList<>();
>> +
>> +    SolrScraperConfig scraperConfig = new SolrScraperConfig();
>> +
>> +    scraperConfig.setJsonQueries(jsonQueries);
>> +
>> +    assertNotNull(scraperConfig.getJsonQueries());
>> +  }
>> +
>> +  @Test
>> +  public void testGetQueryConfig() throws Exception {
>> +    String configFile = getFile("conf/config.yml").getAbsolutePath();
>> +
>> +    SolrCollectorConfig collectorConfig = new Yaml().loadAs(new FileReader(configFile), 
>> SolrCollectorConfig.class);
>> +
>> +    SolrScraperConfig scraperConfig = collectorConfig.getMetrics();
>> +
>> +    assertNotNull(scraperConfig.getQuery());
>> +  }
>> +
>> +  @Test
>> +  public void testSetQueryConfig() throws Exception {
>> +    SolrQueryConfig queryConfig = new SolrQueryConfig();
>> +
>> +    SolrScraperConfig scraperConfig = new SolrScraperConfig();
>> +
>> +    scraperConfig.setQuery(queryConfig);
>> +
>> +    assertNotNull(scraperConfig.getQuery());
>> +  }
>> +}
>>
>> http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/solr-ref-guide/src/images/monitoring-solr-with-prometheus-and-grafana/grafana-solr-dashboard.png
>> ----------------------------------------------------------------------
>> diff --git 
>> a/solr/solr-ref-guide/src/images/monitoring-solr-with-prometheus-and-grafana/grafana-solr-dashboard.png 
>> b/solr/solr-ref-guide/src/images/monitoring-solr-with-prometheus-and-grafana/grafana-solr-dashboard.png
>> new file mode 100644
>> index 0000000..69f21a4
>> Binary files /dev/null and 
>> b/solr/solr-ref-guide/src/images/monitoring-solr-with-prometheus-and-grafana/grafana-solr-dashboard.png 
>> differ
>>
>> http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/solr-ref-guide/src/images/monitoring-solr-with-prometheus-and-grafana/solr-exporter-diagram.png
>> ----------------------------------------------------------------------
>> diff --git 
>> a/solr/solr-ref-guide/src/images/monitoring-solr-with-prometheus-and-grafana/solr-exporter-diagram.png 
>> b/solr/solr-ref-guide/src/images/monitoring-solr-with-prometheus-and-grafana/solr-exporter-diagram.png
>> new file mode 100644
>> index 0000000..96efece
>> Binary files /dev/null and 
>> b/solr/solr-ref-guide/src/images/monitoring-solr-with-prometheus-and-grafana/solr-exporter-diagram.png 
>> differ
>>
>> http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/solr-ref-guide/src/monitoring-solr-with-prometheus-and-grafana.adoc
>> ----------------------------------------------------------------------
>> diff --git a/solr/solr-ref-guide/src/monitoring-solr-with-prometheus-and-grafana.adoc 
>> b/solr/solr-ref-guide/src/monitoring-solr-with-prometheus-and-grafana.adoc
>> new file mode 100644
>> index 0000000..1ac55a2
>> --- /dev/null
>> +++ b/solr/solr-ref-guide/src/monitoring-solr-with-prometheus-and-grafana.adoc
>> @@ -0,0 +1,250 @@
>> += Monitoring Solr with Prometheus and Grafana
>> +// 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.
>> +
>> +You can monitor Solr using solr-exporter that exposes Solr's metrics to 
>> https://prometheus.io[Prometheus], and visualize metrics using https://grafana.com[Grafana].
>> +
>> +It allows users to monitor not only Solr metrics which come from 
>> <<metrics-reporting.adoc#metrics-api,Metrics API>> but also facet counts which come from 
>> <<searching.adoc#searching,Searching>>.
>> +
>> +.solr-exporter Diagram
>> +image::images/monitoring-solr-with-prometheus-and-grafana/solr-exporter-diagram.png[image,width=600]
>> +
>> +This feature is experimental status.
>> +
>> +== Running solr-exporter
>> +
>> +You can start solr-exporter by running `./bin/solr-exporter` from the solr-exporter directory.
>> +
>> +[source,plain]
>> +----
>> +$ cd ./contrib/prometheus-exporter
>> +$ ./bin/solr-exporter -p 9983 -b http://localhost:8983/solr -f ./conf/config.yml -n 8
>> +----
>> +
>> +If you are on Windows platform, you can start solr-exporter by running `.\bin\solr-exporter.cmd` 
>> instead.
>> +
>> +[source,plain]
>> +----
>> +> cd .\contrib\prometheus
>> +> .\bin\solr-exporter.cmd -p 9983 -b http://localhost:8983/solr -f .\conf\config.yml -n 8
>> +----
>> +
>> +You can also connect to Solr in SolrCloud mode like this.
>> +
>> +[source,plain]
>> +----
>> +$ cd ./contrib/prometheus
>> +$ ./bin/solr-exporter -p 9983 -z localhost:2181/solr -f ./conf/config.yml -n 16
>> +----
>> +
>> +See command help:
>> +
>> +[source,plain]
>> +----
>> +$ ./bin/solr-exporter -h
>> +usage: SolrCollector [-h] [-v] [-p PORT] [-b BASE_URL] [-z ZK_HOST] [-f CONFIG]
>> +                     [-n NUM_THREADS]
>> +
>> +Prometheus exporter for Apache Solr.
>> +
>> +optional arguments:
>> +  -h, --help             show this help message and exit
>> +  -p PORT, --port PORT   solr-exporter listen port
>> +  -b BASE_URL, --baseurl BASE_URL
>> +                         specify Solr base URL when connecting  to Solr in standalone mode (for
>> +                         example 'http://localhost:8983/solr')
>> +  -z ZK_HOST, --zkhost ZK_HOST
>> +                         specify  ZooKeeper  connection  string  when  connecting  to  Solr  in
>> +                         SolrCloud mode (for example 'localhost:2181/solr')
>> +  -f CONFIG, --config-file CONFIG
>> +                         specify configuration file
>> +  -n NUM_THREADS, --num-thread NUM_THREADS
>> +                         specify number of threads
>> +----
>> +
>> +The Solr's metrics exposed by solr-exporter can see at the following URL.
>> +
>> +http://localhost:9983/metrics[http://localhost:9983/metrics]
>> +
>> +
>> +== Configuration
>> +
>> +The configuration is in `./config/config.yml`. An example with all possible options:
>> +
>> +[source,plain]
>> +----
>> +ping:
>> +  query:
>> +    path: /admin/ping
>> +  jsonQueries:
>> +    - |-
>> +      . as $object | $object |
>> +      (if $object.status == "OK" then 1.0 else 0.0 end) as $value |
>> +      {
>> +        name         : "solr_ping",
>> +        type         : "GAUGE",
>> +        help         : "See following URL: https://lucene.apache.org/solr/guide/ping.html",
>> +        label_names  : [],
>> +        label_values : [],
>> +        value        : $value
>> +      }
>> +
>> +metrics:
>> +  query:
>> +    path: /admin/metrics
>> +    params:
>> +      - group: 'all'
>> +      - type: 'all'
>> +      - prefix: ''
>> +      - property: ''
>> +  jsonQueries:
>> +    # solr_metrics_jetty_response_count
>> +    - |-
>> +      .metrics["solr.jetty"] | to_entries | .[] | select(.key | 
>> startswith("org.eclipse.jetty.server.handler.DefaultHandler")) | select(.key | 
>> endswith("xx-responses")) as $object |
>> +      $object.key | split(".") | last | split("-") | first as $status |
>> +      $object.value.count as $value |
>> +      {
>> +        name         : "solr_metrics_jetty_response_count",
>> +        type         : "gauge",
>> +        help         : "See following URL: 
>> https://lucene.apache.org/solr/guide/metrics-reporting.html",
>> +        label_names  : ["status"],
>> +        label_values : [$status],
>> +        value        : $value
>> +      }
>> +
>> +...
>> +
>> +collections:
>> +  query:
>> +    path: /admin/collections
>> +    params:
>> +      - action: 'CLUSTERSTATUS'
>> +  jsonQueries:
>> +    # solr_collections_cluster_status_live_nodes
>> +    - |-
>> +      .cluster.live_nodes | length as $value|
>> +      {
>> +        name         : "solr_collections_cluster_status_live_nodes",
>> +        type         : "gauge",
>> +        help         : "See following URL: 
>> https://lucene.apache.org/solr/guide/collections-api.html#clusterstatus",
>> +        label_names  : [],
>> +        label_values : [],
>> +        value        : $value
>> +      }
>> +
>> +...
>> +
>> +queries:
>> +  - query:
>> +      collection: collection1
>> +      path: /select
>> +      params:
>> +        - q: "*:*"
>> +        - start: 0
>> +        - rows: 0
>> +        - json.facet: |-
>> +            {
>> +              category: {
>> +                type: terms,
>> +                field: cat
>> +              }
>> +            }
>> +    jsonQueries:
>> +      # solr_facets_category
>> +      - |-
>> +        .facets.category.buckets[] as $object |
>> +        $object.val as $term |
>> +        $object.count as $value |
>> +        {
>> +          name         : "solr_facets_category",
>> +          type         : "gauge",
>> +          help         : "Category facets",
>> +          label_names  : ["term"],
>> +          label_values : [$term],
>> +          value        : $value
>> +        }
>> +----
>> +
>> +|===
>> +|Name|Description
>> +
>> +|ping|Scrape <<ping.adoc#ping,Ping>> response.
>> +|metrics|Scrape <<metrics-reporting.adoc#metrics-api,Metrics API>> response.
>> +|collections|Scrape <<collections-api.adoc#collections-api,Collections API>> response.
>> +|queries|Scrape <<searching.adoc#searching,Search API>> response.
>> +|*.query|Query parameter for each features. You can specify `collection`, `core`, `path`, and 
>> `params`.
>> +|*.jsonQueries|JSON Query that is jq syntax. For more details, see 
>> https://stedolan.github.io/jq/manual/[https://stedolan.github.io/jq/manual/].
>> +|===
>> +
>> +jq query has to output JSON in the following format.
>> +
>> +[source,json]
>> +----
>> +{
>> +  name         : "solr_ping",
>> +  type         : "GAUGE",
>> +  help         : "See following URL: https://lucene.apache.org/solr/guide/ping.html",
>> +  label_names  : ["base_url","core"],
>> +  label_values : ["http://localhost:8983/solr","collection1"],
>> +  value        : 1.0
>> +}
>> +----
>> +
>> +It will be converted to the following exposition format.
>> +
>> +[source,plain]
>> +----
>> +# TYPE solr_ping gauge
>> +# HELP solr_ping See following URL: https://lucene.apache.org/solr/guide/ping.html
>> +solr_ping{base_url="http://localhost:8983/solr",core="collection1"} 1.0
>> +----
>> +
>> +|===
>> +|Name|Description
>> +
>> +|name|The metric name to set. For more details, see 
>> https://prometheus.io/docs/practices/naming/[https://prometheus.io/docs/practices/naming/].
>> +|type|The type of the metric, can be `COUNTER`, `GAUGE`, `SUMMARY`, `HISTOGRAM` or `UNTYPED`. For 
>> more detauils, see 
>> https://prometheus.io/docs/concepts/metric_types/[https://prometheus.io/docs/concepts/metric_types/].
>> +|help|Help text for the metric.
>> +|label_names|Label names for the metric. For more details, see 
>> https://prometheus.io/docs/practices/naming/[https://prometheus.io/docs/practices/naming/].
>> +|label_values|Label values for the metric. For more details, see 
>> https://prometheus.io/docs/practices/naming/[https://prometheus.io/docs/practices/naming/].
>> +|value|Value for the metric. Value must be set to Double type.
>> +|===
>> +
>> +
>> +== Prometheus Settings
>> +
>> +You need to specify the solr-exporter listen address into `scrape_configs` in `prometheus.yml`. 
>> See following example:
>> +
>> +[source,plain]
>> +----
>> +scrape_configs:
>> +  - job_name: 'solr'
>> +    static_configs:
>> +      - targets: ['localhost:9983']
>> +----
>> +
>> +When you apply the above settings to prometheus, it will start to pull Solr's metrics from 
>> solr-exporter.
>> +
>> +
>> +== Grafana Dashboard
>> +
>> +A Grafana sample dashboard is provided at the following JSON file.
>> +
>> +`./conf/grafana-solr-dashboard.json`
>> +
>> +.Grafana Dashboard
>> +image::images/monitoring-solr-with-prometheus-and-grafana/grafana-solr-dashboard.png[image,width=800]
>>
>> http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/solr-ref-guide/src/monitoring-solr.adoc
>> ----------------------------------------------------------------------
>> diff --git a/solr/solr-ref-guide/src/monitoring-solr.adoc 
>> b/solr/solr-ref-guide/src/monitoring-solr.adoc
>> index 0576e53..2fb7077 100644
>> --- a/solr/solr-ref-guide/src/monitoring-solr.adoc
>> +++ b/solr/solr-ref-guide/src/monitoring-solr.adoc
>> @@ -1,5 +1,5 @@
>> = Monitoring Solr
>> -:page-children: metrics-reporting, mbean-request-handler, configuring-logging, 
>> using-jmx-with-solr, performance-statistics-reference
>> +:page-children: metrics-reporting, mbean-request-handler, configuring-logging, 
>> using-jmx-with-solr, monitoring-solr-with-prometheus-and-grafana, performance-statistics-reference
>> // 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
>> @@ -30,6 +30,8 @@ Common administrative tasks include:
>>
>> <<using-jmx-with-solr.adoc#using-jmx-with-solr,Using JMX with Solr>>: Describes how to use Java 
>> Management Extensions with Solr.
>>
>> +<<monitoring-solr-with-prometheus-and-grafana.adoc#monitoring-solr-with-prometheus-and-grafana,Monitoring 
>> Solr with Prometheus and Grafana>>: Describes how to monitor Solr with Prometheus and Grafana.
>> +
>> <<performance-statistics-reference.adoc#performance-statistics-reference,Performance Statistics 
>> Reference>>: Additional information on statistics returned from JMX.
>>
>>
>>
> 

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@lucene.apache.org
For additional commands, e-mail: dev-help@lucene.apache.org


Re: [1/7] lucene-solr:master: SOLR-11795: Add Solr metrics exporter for Prometheus

Posted by Andrzej Białecki <an...@lucidworks.com>.
Builds on jenkins are failing due to precommit failures in this code...

> On 20 Feb 2018, at 09:47, koji@apache.org wrote:
> 
> Repository: lucene-solr
> Updated Branches:
>  refs/heads/master dfc0fe86e -> 4bfcbc5c6
> 
> 
> http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/config/SolrQueryConfigTest.java
> ----------------------------------------------------------------------
> diff --git a/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/config/SolrQueryConfigTest.java b/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/config/SolrQueryConfigTest.java
> new file mode 100644
> index 0000000..c62d354
> --- /dev/null
> +++ b/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/config/SolrQueryConfigTest.java
> @@ -0,0 +1,121 @@
> +/*
> + * 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.prometheus.scraper.config;
> +
> +import org.apache.solr.SolrTestCaseJ4;
> +import org.junit.Test;
> +
> +import java.util.ArrayList;
> +import java.util.Arrays;
> +import java.util.LinkedHashMap;
> +import java.util.List;
> +
> +/**
> + * Unit test for SolrQueryConfig.
> + */
> +public class SolrQueryConfigTest extends SolrTestCaseJ4 {
> +  @Test
> +  public void testQueryConfig() throws Exception {
> +    SolrQueryConfig queryConfig = new SolrQueryConfig();
> +
> +    assertNotNull(queryConfig);
> +  }
> +
> +  @Test
> +  public void testGetCollection() throws Exception {
> +    SolrQueryConfig queryConfig = new SolrQueryConfig();
> +
> +    String expected = "";
> +    String actual = queryConfig.getCollection();
> +    assertEquals(expected, actual);
> +  }
> +
> +  @Test
> +  public void testSetCollection() throws Exception {
> +    SolrQueryConfig queryConfig = new SolrQueryConfig();
> +
> +    queryConfig.setCollection("collection1");
> +
> +    String expected = "collection1";
> +    String actual = queryConfig.getCollection();
> +    assertEquals(expected, actual);
> +  }
> +
> +  @Test
> +  public void testGetPath() throws Exception {
> +    SolrQueryConfig queryConfig = new SolrQueryConfig();
> +
> +    String expected = "";
> +    String actual = queryConfig.getPath();
> +    assertEquals(expected, actual);
> +  }
> +
> +  @Test
> +  public void testSetPath() throws Exception {
> +    SolrQueryConfig queryConfig = new SolrQueryConfig();
> +
> +    queryConfig.setPath("/select");
> +
> +    String expected = "/select";
> +    String actual = queryConfig.getPath();
> +    assertEquals(expected, actual);
> +  }
> +
> +  @Test
> +  public void testGetParams() throws Exception {
> +    SolrQueryConfig queryConfig = new SolrQueryConfig();
> +
> +    List<LinkedHashMap<String, String>> expected = new ArrayList<>();
> +    List<LinkedHashMap<String, String>> actual = queryConfig.getParams();
> +    assertEquals(expected, actual);
> +  }
> +
> +  @Test
> +  public void testSetParams() throws Exception {
> +    SolrQueryConfig queryConfig = new SolrQueryConfig();
> +
> +    LinkedHashMap<String,String> param1 = new LinkedHashMap<>();
> +    param1.put("q", "*:*");
> +
> +    LinkedHashMap<String,String> param2 = new LinkedHashMap<>();
> +    param2.put("facet", "on");
> +
> +    queryConfig.setParams(Arrays.asList(param1, param2));
> +
> +    List<LinkedHashMap<String, String>> expected = Arrays.asList(param1, param2);
> +    List<LinkedHashMap<String, String>> actual = queryConfig.getParams();
> +    assertEquals(expected, actual);
> +  }
> +
> +  @Test
> +  public void testGetParamsString() throws Exception {
> +    SolrQueryConfig queryConfig = new SolrQueryConfig();
> +
> +    LinkedHashMap<String,String> param1 = new LinkedHashMap<>();
> +    param1.put("q", "*:*");
> +    param1.put("fq", "manu:apple");
> +
> +    LinkedHashMap<String,String> param2 = new LinkedHashMap<>();
> +    param2.put("facet", "on");
> +
> +    queryConfig.setParams(Arrays.asList(param1, param2));
> +
> +    String expected = "q=*:*&fq=manu:apple&facet=on";
> +    String actual = queryConfig.getParamsString();
> +    assertEquals(expected, actual);
> +  }
> +}
> 
> http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/config/SolrScraperConfigTest.java
> ----------------------------------------------------------------------
> diff --git a/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/config/SolrScraperConfigTest.java b/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/config/SolrScraperConfigTest.java
> new file mode 100644
> index 0000000..79d1204
> --- /dev/null
> +++ b/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/config/SolrScraperConfigTest.java
> @@ -0,0 +1,86 @@
> +/*
> + * 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.prometheus.scraper.config;
> +
> +import org.apache.solr.prometheus.collector.config.SolrCollectorConfig;
> +import org.apache.solr.SolrTestCaseJ4;
> +import org.junit.Test;
> +import org.yaml.snakeyaml.Yaml;
> +
> +import java.io.FileReader;
> +import java.util.ArrayList;
> +import java.util.List;
> +
> +/**
> + * Unit test for SolrScraperConfig.
> + */
> +public class SolrScraperConfigTest extends SolrTestCaseJ4 {
> +  @Test
> +  public void testScraperConfig() throws Exception {
> +    String configFile = getFile("conf/config.yml").getAbsolutePath();
> +
> +    SolrCollectorConfig config = new Yaml().loadAs(new FileReader(configFile), SolrCollectorConfig.class);
> +
> +    SolrScraperConfig scraperConfig = config.getMetrics();
> +
> +    assertNotNull(scraperConfig);
> +  }
> +
> +  @Test
> +  public void testGetJsonQueries() throws Exception {
> +    String configFile = getFile("conf/config.yml").getAbsolutePath();
> +
> +    SolrCollectorConfig collectorConfig = new Yaml().loadAs(new FileReader(configFile), SolrCollectorConfig.class);
> +
> +    SolrScraperConfig scraperConfig = collectorConfig.getMetrics();
> +
> +    assertNotNull(scraperConfig.getJsonQueries());
> +  }
> +
> +  @Test
> +  public void testSetJsonQueries() throws Exception {
> +    List<String> jsonQueries = new ArrayList<>();
> +
> +    SolrScraperConfig scraperConfig = new SolrScraperConfig();
> +
> +    scraperConfig.setJsonQueries(jsonQueries);
> +
> +    assertNotNull(scraperConfig.getJsonQueries());
> +  }
> +
> +  @Test
> +  public void testGetQueryConfig() throws Exception {
> +    String configFile = getFile("conf/config.yml").getAbsolutePath();
> +
> +    SolrCollectorConfig collectorConfig = new Yaml().loadAs(new FileReader(configFile), SolrCollectorConfig.class);
> +
> +    SolrScraperConfig scraperConfig = collectorConfig.getMetrics();
> +
> +    assertNotNull(scraperConfig.getQuery());
> +  }
> +
> +  @Test
> +  public void testSetQueryConfig() throws Exception {
> +    SolrQueryConfig queryConfig = new SolrQueryConfig();
> +
> +    SolrScraperConfig scraperConfig = new SolrScraperConfig();
> +
> +    scraperConfig.setQuery(queryConfig);
> +
> +    assertNotNull(scraperConfig.getQuery());
> +  }
> +}
> 
> http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/solr-ref-guide/src/images/monitoring-solr-with-prometheus-and-grafana/grafana-solr-dashboard.png
> ----------------------------------------------------------------------
> diff --git a/solr/solr-ref-guide/src/images/monitoring-solr-with-prometheus-and-grafana/grafana-solr-dashboard.png b/solr/solr-ref-guide/src/images/monitoring-solr-with-prometheus-and-grafana/grafana-solr-dashboard.png
> new file mode 100644
> index 0000000..69f21a4
> Binary files /dev/null and b/solr/solr-ref-guide/src/images/monitoring-solr-with-prometheus-and-grafana/grafana-solr-dashboard.png differ
> 
> http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/solr-ref-guide/src/images/monitoring-solr-with-prometheus-and-grafana/solr-exporter-diagram.png
> ----------------------------------------------------------------------
> diff --git a/solr/solr-ref-guide/src/images/monitoring-solr-with-prometheus-and-grafana/solr-exporter-diagram.png b/solr/solr-ref-guide/src/images/monitoring-solr-with-prometheus-and-grafana/solr-exporter-diagram.png
> new file mode 100644
> index 0000000..96efece
> Binary files /dev/null and b/solr/solr-ref-guide/src/images/monitoring-solr-with-prometheus-and-grafana/solr-exporter-diagram.png differ
> 
> http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/solr-ref-guide/src/monitoring-solr-with-prometheus-and-grafana.adoc
> ----------------------------------------------------------------------
> diff --git a/solr/solr-ref-guide/src/monitoring-solr-with-prometheus-and-grafana.adoc b/solr/solr-ref-guide/src/monitoring-solr-with-prometheus-and-grafana.adoc
> new file mode 100644
> index 0000000..1ac55a2
> --- /dev/null
> +++ b/solr/solr-ref-guide/src/monitoring-solr-with-prometheus-and-grafana.adoc
> @@ -0,0 +1,250 @@
> += Monitoring Solr with Prometheus and Grafana
> +// 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.
> +
> +You can monitor Solr using solr-exporter that exposes Solr's metrics to https://prometheus.io[Prometheus], and visualize metrics using https://grafana.com[Grafana].
> +
> +It allows users to monitor not only Solr metrics which come from <<metrics-reporting.adoc#metrics-api,Metrics API>> but also facet counts which come from <<searching.adoc#searching,Searching>>.
> +
> +.solr-exporter Diagram
> +image::images/monitoring-solr-with-prometheus-and-grafana/solr-exporter-diagram.png[image,width=600]
> +
> +This feature is experimental status.
> +
> +== Running solr-exporter
> +
> +You can start solr-exporter by running `./bin/solr-exporter` from the solr-exporter directory.
> +
> +[source,plain]
> +----
> +$ cd ./contrib/prometheus-exporter
> +$ ./bin/solr-exporter -p 9983 -b http://localhost:8983/solr -f ./conf/config.yml -n 8
> +----
> +
> +If you are on Windows platform, you can start solr-exporter by running `.\bin\solr-exporter.cmd` instead.
> +
> +[source,plain]
> +----
> +> cd .\contrib\prometheus
> +> .\bin\solr-exporter.cmd -p 9983 -b http://localhost:8983/solr -f .\conf\config.yml -n 8
> +----
> +
> +You can also connect to Solr in SolrCloud mode like this.
> +
> +[source,plain]
> +----
> +$ cd ./contrib/prometheus
> +$ ./bin/solr-exporter -p 9983 -z localhost:2181/solr -f ./conf/config.yml -n 16
> +----
> +
> +See command help:
> +
> +[source,plain]
> +----
> +$ ./bin/solr-exporter -h
> +usage: SolrCollector [-h] [-v] [-p PORT] [-b BASE_URL] [-z ZK_HOST] [-f CONFIG]
> +                     [-n NUM_THREADS]
> +
> +Prometheus exporter for Apache Solr.
> +
> +optional arguments:
> +  -h, --help             show this help message and exit
> +  -p PORT, --port PORT   solr-exporter listen port
> +  -b BASE_URL, --baseurl BASE_URL
> +                         specify Solr base URL when connecting  to Solr in standalone mode (for
> +                         example 'http://localhost:8983/solr')
> +  -z ZK_HOST, --zkhost ZK_HOST
> +                         specify  ZooKeeper  connection  string  when  connecting  to  Solr  in
> +                         SolrCloud mode (for example 'localhost:2181/solr')
> +  -f CONFIG, --config-file CONFIG
> +                         specify configuration file
> +  -n NUM_THREADS, --num-thread NUM_THREADS
> +                         specify number of threads
> +----
> +
> +The Solr's metrics exposed by solr-exporter can see at the following URL.
> +
> +http://localhost:9983/metrics[http://localhost:9983/metrics]
> +
> +
> +== Configuration
> +
> +The configuration is in `./config/config.yml`. An example with all possible options:
> +
> +[source,plain]
> +----
> +ping:
> +  query:
> +    path: /admin/ping
> +  jsonQueries:
> +    - |-
> +      . as $object | $object |
> +      (if $object.status == "OK" then 1.0 else 0.0 end) as $value |
> +      {
> +        name         : "solr_ping",
> +        type         : "GAUGE",
> +        help         : "See following URL: https://lucene.apache.org/solr/guide/ping.html",
> +        label_names  : [],
> +        label_values : [],
> +        value        : $value
> +      }
> +
> +metrics:
> +  query:
> +    path: /admin/metrics
> +    params:
> +      - group: 'all'
> +      - type: 'all'
> +      - prefix: ''
> +      - property: ''
> +  jsonQueries:
> +    # solr_metrics_jetty_response_count
> +    - |-
> +      .metrics["solr.jetty"] | to_entries | .[] | select(.key | startswith("org.eclipse.jetty.server.handler.DefaultHandler")) | select(.key | endswith("xx-responses")) as $object |
> +      $object.key | split(".") | last | split("-") | first as $status |
> +      $object.value.count as $value |
> +      {
> +        name         : "solr_metrics_jetty_response_count",
> +        type         : "gauge",
> +        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
> +        label_names  : ["status"],
> +        label_values : [$status],
> +        value        : $value
> +      }
> +
> +...
> +
> +collections:
> +  query:
> +    path: /admin/collections
> +    params:
> +      - action: 'CLUSTERSTATUS'
> +  jsonQueries:
> +    # solr_collections_cluster_status_live_nodes
> +    - |-
> +      .cluster.live_nodes | length as $value|
> +      {
> +        name         : "solr_collections_cluster_status_live_nodes",
> +        type         : "gauge",
> +        help         : "See following URL: https://lucene.apache.org/solr/guide/collections-api.html#clusterstatus",
> +        label_names  : [],
> +        label_values : [],
> +        value        : $value
> +      }
> +
> +...
> +
> +queries:
> +  - query:
> +      collection: collection1
> +      path: /select
> +      params:
> +        - q: "*:*"
> +        - start: 0
> +        - rows: 0
> +        - json.facet: |-
> +            {
> +              category: {
> +                type: terms,
> +                field: cat
> +              }
> +            }
> +    jsonQueries:
> +      # solr_facets_category
> +      - |-
> +        .facets.category.buckets[] as $object |
> +        $object.val as $term |
> +        $object.count as $value |
> +        {
> +          name         : "solr_facets_category",
> +          type         : "gauge",
> +          help         : "Category facets",
> +          label_names  : ["term"],
> +          label_values : [$term],
> +          value        : $value
> +        }
> +----
> +
> +|===
> +|Name|Description
> +
> +|ping|Scrape <<ping.adoc#ping,Ping>> response.
> +|metrics|Scrape <<metrics-reporting.adoc#metrics-api,Metrics API>> response.
> +|collections|Scrape <<collections-api.adoc#collections-api,Collections API>> response.
> +|queries|Scrape <<searching.adoc#searching,Search API>> response.
> +|*.query|Query parameter for each features. You can specify `collection`, `core`, `path`, and `params`.
> +|*.jsonQueries|JSON Query that is jq syntax. For more details, see https://stedolan.github.io/jq/manual/[https://stedolan.github.io/jq/manual/].
> +|===
> +
> +jq query has to output JSON in the following format.
> +
> +[source,json]
> +----
> +{
> +  name         : "solr_ping",
> +  type         : "GAUGE",
> +  help         : "See following URL: https://lucene.apache.org/solr/guide/ping.html",
> +  label_names  : ["base_url","core"],
> +  label_values : ["http://localhost:8983/solr","collection1"],
> +  value        : 1.0
> +}
> +----
> +
> +It will be converted to the following exposition format.
> +
> +[source,plain]
> +----
> +# TYPE solr_ping gauge
> +# HELP solr_ping See following URL: https://lucene.apache.org/solr/guide/ping.html
> +solr_ping{base_url="http://localhost:8983/solr",core="collection1"} 1.0
> +----
> +
> +|===
> +|Name|Description
> +
> +|name|The metric name to set. For more details, see https://prometheus.io/docs/practices/naming/[https://prometheus.io/docs/practices/naming/].
> +|type|The type of the metric, can be `COUNTER`, `GAUGE`, `SUMMARY`, `HISTOGRAM` or `UNTYPED`. For more detauils, see https://prometheus.io/docs/concepts/metric_types/[https://prometheus.io/docs/concepts/metric_types/].
> +|help|Help text for the metric.
> +|label_names|Label names for the metric. For more details, see https://prometheus.io/docs/practices/naming/[https://prometheus.io/docs/practices/naming/].
> +|label_values|Label values for the metric. For more details, see https://prometheus.io/docs/practices/naming/[https://prometheus.io/docs/practices/naming/].
> +|value|Value for the metric. Value must be set to Double type.
> +|===
> +
> +
> +== Prometheus Settings
> +
> +You need to specify the solr-exporter listen address into `scrape_configs` in `prometheus.yml`. See following example:
> +
> +[source,plain]
> +----
> +scrape_configs:
> +  - job_name: 'solr'
> +    static_configs:
> +      - targets: ['localhost:9983']
> +----
> +
> +When you apply the above settings to prometheus, it will start to pull Solr's metrics from solr-exporter.
> +
> +
> +== Grafana Dashboard
> +
> +A Grafana sample dashboard is provided at the following JSON file.
> +
> +`./conf/grafana-solr-dashboard.json`
> +
> +.Grafana Dashboard
> +image::images/monitoring-solr-with-prometheus-and-grafana/grafana-solr-dashboard.png[image,width=800]
> 
> http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/solr-ref-guide/src/monitoring-solr.adoc
> ----------------------------------------------------------------------
> diff --git a/solr/solr-ref-guide/src/monitoring-solr.adoc b/solr/solr-ref-guide/src/monitoring-solr.adoc
> index 0576e53..2fb7077 100644
> --- a/solr/solr-ref-guide/src/monitoring-solr.adoc
> +++ b/solr/solr-ref-guide/src/monitoring-solr.adoc
> @@ -1,5 +1,5 @@
> = Monitoring Solr
> -:page-children: metrics-reporting, mbean-request-handler, configuring-logging, using-jmx-with-solr, performance-statistics-reference
> +:page-children: metrics-reporting, mbean-request-handler, configuring-logging, using-jmx-with-solr, monitoring-solr-with-prometheus-and-grafana, performance-statistics-reference
> // 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
> @@ -30,6 +30,8 @@ Common administrative tasks include:
> 
> <<using-jmx-with-solr.adoc#using-jmx-with-solr,Using JMX with Solr>>: Describes how to use Java Management Extensions with Solr.
> 
> +<<monitoring-solr-with-prometheus-and-grafana.adoc#monitoring-solr-with-prometheus-and-grafana,Monitoring Solr with Prometheus and Grafana>>: Describes how to monitor Solr with Prometheus and Grafana.
> +
> <<performance-statistics-reference.adoc#performance-statistics-reference,Performance Statistics Reference>>: Additional information on statistics returned from JMX.
> 
> 
> 


[2/7] lucene-solr:master: SOLR-11795: Add Solr metrics exporter for Prometheus

Posted by ko...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/test-files/conf/log4j.properties
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/src/test-files/conf/log4j.properties b/solr/contrib/prometheus-exporter/src/test-files/conf/log4j.properties
new file mode 100644
index 0000000..5dd6899
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/src/test-files/conf/log4j.properties
@@ -0,0 +1,22 @@
+#
+# 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.
+#
+
+log4j.rootLogger=INFO, stdout
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.Target=System.out
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd'T'HH:mm:ss.SSS} %-5p [%c] - %m%n

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/test-files/configsets/collection1/conf/managed-schema
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/src/test-files/configsets/collection1/conf/managed-schema b/solr/contrib/prometheus-exporter/src/test-files/configsets/collection1/conf/managed-schema
new file mode 100644
index 0000000..caa3317
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/src/test-files/configsets/collection1/conf/managed-schema
@@ -0,0 +1,412 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ 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.
+-->
+
+<!--
+
+ This example schema is the recommended starting point for users.
+ It should be kept correct and concise, usable out-of-the-box.
+
+
+ For more information, on how to customize this file, please see
+ http://lucene.apache.org/solr/guide/documents-fields-and-schema-design.html
+
+ PERFORMANCE NOTE: this schema includes many optional features and should not
+ be used for benchmarking.  To improve performance one could
+  - set stored="false" for all fields possible (esp large fields) when you
+    only need to search on the field but don't need to return the original
+    value.
+  - set indexed="false" if you don't need to search on the field, but only
+    return the field as a result of searching on other indexed fields.
+  - remove all unneeded copyField statements
+  - for best index size and searching performance, set "index" to false
+    for all general text fields, use copyField to copy them to the
+    catchall "text" field, and use that for searching.
+-->
+
+<schema name="collection1-config" version="1.6">
+    <!-- attribute "name" is the name of this schema and is only used for display purposes.
+       version="x.y" is Solr's version number for the schema syntax and
+       semantics.  It should not normally be changed by applications.
+
+       1.0: multiValued attribute did not exist, all fields are multiValued
+            by nature
+       1.1: multiValued attribute introduced, false by default
+       1.2: omitTermFreqAndPositions attribute introduced, true by default
+            except for text fields.
+       1.3: removed optional field compress feature
+       1.4: autoGeneratePhraseQueries attribute introduced to drive QueryParser
+            behavior when a single string produces multiple tokens.  Defaults
+            to off for version >= 1.4
+       1.5: omitNorms defaults to true for primitive field types
+            (int, float, boolean, string...)
+       1.6: useDocValuesAsStored defaults to true.
+    -->
+
+    <!-- Valid attributes for fields:
+     name: mandatory - the name for the field
+     type: mandatory - the name of a field type from the
+       fieldTypes section
+     indexed: true if this field should be indexed (searchable or sortable)
+     stored: true if this field should be retrievable
+     docValues: true if this field should have doc values. Doc Values is
+       recommended (required, if you are using *Point fields) for faceting,
+       grouping, sorting and function queries. Doc Values will make the index
+       faster to load, more NRT-friendly and more memory-efficient.
+       They are currently only supported by StrField, UUIDField, all
+       *PointFields, and depending on the field type, they might require
+       the field to be single-valued, be required or have a default value
+       (check the documentation of the field type you're interested in for
+       more information)
+     multiValued: true if this field may contain multiple values per document
+     omitNorms: (expert) set to true to omit the norms associated with
+       this field (this disables length normalization and index-time
+       boosting for the field, and saves some memory).  Only full-text
+       fields or fields that need an index-time boost need norms.
+       Norms are omitted for primitive (non-analyzed) types by default.
+     termVectors: [false] set to true to store the term vector for a
+       given field.
+       When using MoreLikeThis, fields used for similarity should be
+       stored for best performance.
+     termPositions: Store position information with the term vector.
+       This will increase storage costs.
+     termOffsets: Store offset information with the term vector. This
+       will increase storage costs.
+     required: The field is required.  It will throw an error if the
+       value does not exist
+     default: a value that should be used if no value is specified
+       when adding a document.
+    -->
+
+    <!-- field names should consist of alphanumeric or underscore characters only and
+      not start with a digit.  This is not currently strictly enforced,
+      but other field names will not have first class support from all components
+      and back compatibility is not guaranteed.  Names with both leading and
+      trailing underscores (e.g. _version_) are reserved.
+    -->
+
+    <!-- In this _default configset, only four fields are pre-declared:
+         id, _version_, and _text_ and _root_. All other fields will be type guessed and added via the
+         "add-unknown-fields-to-the-schema" update request processor chain declared in solrconfig.xml.
+
+         Note that many dynamic fields are also defined - you can use them to specify a
+         field's type via field naming conventions - see below.
+
+         WARNING: The _text_ catch-all field will significantly increase your index size.
+         If you don't need it, consider removing it and the corresponding copyField directive.
+    -->
+
+    <field name="id" type="string" indexed="true" stored="true" required="true" multiValued="false" />
+    <!-- docValues are enabled by default for long type so we don't need to index the version field  -->
+    <field name="_version_" type="plong" indexed="false" stored="false"/>
+    <field name="_root_" type="string" indexed="true" stored="false" docValues="false" />
+    <field name="_text_" type="text_general" indexed="true" stored="false" multiValued="true"/>
+
+    <!-- This can be enabled, in case the client does not know what fields may be searched. It isn't enabled by default
+         because it's very expensive to index everything twice. -->
+    <!-- <copyField source="*" dest="_text_"/> -->
+
+    <!-- Dynamic field definitions allow using convention over configuration
+       for fields via the specification of patterns to match field names.
+       EXAMPLE:  name="*_i" will match any field ending in _i (like myid_i, z_i)
+       RESTRICTION: the glob-like pattern in the name attribute must have a "*" only at the start or the end.  -->
+
+    <dynamicField name="*_i"  type="pint"    indexed="true"  stored="true"/>
+    <dynamicField name="*_is" type="pints"    indexed="true"  stored="true"/>
+    <dynamicField name="*_s"  type="string"  indexed="true"  stored="true" />
+    <dynamicField name="*_ss" type="strings"  indexed="true"  stored="true"/>
+    <dynamicField name="*_l"  type="plong"   indexed="true"  stored="true"/>
+    <dynamicField name="*_ls" type="plongs"   indexed="true"  stored="true"/>
+    <dynamicField name="*_txt" type="text_general" indexed="true" stored="true"/>
+    <dynamicField name="*_b"  type="boolean" indexed="true" stored="true"/>
+    <dynamicField name="*_bs" type="booleans" indexed="true" stored="true"/>
+    <dynamicField name="*_f"  type="pfloat"  indexed="true"  stored="true"/>
+    <dynamicField name="*_fs" type="pfloats"  indexed="true"  stored="true"/>
+    <dynamicField name="*_d"  type="pdouble" indexed="true"  stored="true"/>
+    <dynamicField name="*_ds" type="pdoubles" indexed="true"  stored="true"/>
+
+    <!-- Type used for data-driven schema, to add a string copy for each text field -->
+    <dynamicField name="*_str" type="strings" stored="false" docValues="true" indexed="false" />
+
+    <dynamicField name="*_dt"  type="pdate"    indexed="true"  stored="true"/>
+    <dynamicField name="*_dts" type="pdate"    indexed="true"  stored="true" multiValued="true"/>
+    <dynamicField name="*_p"  type="location" indexed="true" stored="true"/>
+    <dynamicField name="*_srpt"  type="location_rpt" indexed="true" stored="true"/>
+
+    <!-- payloaded dynamic fields -->
+    <dynamicField name="*_dpf" type="delimited_payloads_float" indexed="true"  stored="true"/>
+    <dynamicField name="*_dpi" type="delimited_payloads_int" indexed="true"  stored="true"/>
+    <dynamicField name="*_dps" type="delimited_payloads_string" indexed="true"  stored="true"/>
+
+    <dynamicField name="attr_*" type="text_general" indexed="true" stored="true" multiValued="true"/>
+
+    <!-- Field to use to determine and enforce document uniqueness.
+      Unless this field is marked with required="false", it will be a required field
+    -->
+    <uniqueKey>id</uniqueKey>
+
+    <!-- copyField commands copy one field to another at the time a document
+       is added to the index.  It's used either to index the same field differently,
+       or to add multiple fields to the same field for easier/faster searching.
+
+    <copyField source="sourceFieldName" dest="destinationFieldName"/>
+    -->
+
+    <!-- field type definitions. The "name" attribute is
+       just a label to be used by field definitions.  The "class"
+       attribute and any other attributes determine the real
+       behavior of the fieldType.
+         Class names starting with "solr" refer to java classes in a
+       standard package such as org.apache.solr.analysis
+    -->
+
+    <!-- sortMissingLast and sortMissingFirst attributes are optional attributes are
+         currently supported on types that are sorted internally as strings
+         and on numeric types.
+       This includes "string", "boolean", "pint", "pfloat", "plong", "pdate", "pdouble".
+       - If sortMissingLast="true", then a sort on this field will cause documents
+         without the field to come after documents with the field,
+         regardless of the requested sort order (asc or desc).
+       - If sortMissingFirst="true", then a sort on this field will cause documents
+         without the field to come before documents with the field,
+         regardless of the requested sort order.
+       - If sortMissingLast="false" and sortMissingFirst="false" (the default),
+         then default lucene sorting will be used which places docs without the
+         field first in an ascending sort and last in a descending sort.
+    -->
+
+    <!-- The StrField type is not analyzed, but indexed/stored verbatim. -->
+    <fieldType name="string" class="solr.StrField" sortMissingLast="true" docValues="true" />
+    <fieldType name="strings" class="solr.StrField" sortMissingLast="true" multiValued="true" docValues="true" />
+
+    <!-- boolean type: "true" or "false" -->
+    <fieldType name="boolean" class="solr.BoolField" sortMissingLast="true"/>
+    <fieldType name="booleans" class="solr.BoolField" sortMissingLast="true" multiValued="true"/>
+
+    <!--
+      Numeric field types that index values using KD-trees.
+      Point fields don't support FieldCache, so they must have docValues="true" if needed for sorting, faceting, functions, etc.
+    -->
+    <fieldType name="pint" class="solr.IntPointField" docValues="true"/>
+    <fieldType name="pfloat" class="solr.FloatPointField" docValues="true"/>
+    <fieldType name="plong" class="solr.LongPointField" docValues="true"/>
+    <fieldType name="pdouble" class="solr.DoublePointField" docValues="true"/>
+
+    <fieldType name="pints" class="solr.IntPointField" docValues="true" multiValued="true"/>
+    <fieldType name="pfloats" class="solr.FloatPointField" docValues="true" multiValued="true"/>
+    <fieldType name="plongs" class="solr.LongPointField" docValues="true" multiValued="true"/>
+    <fieldType name="pdoubles" class="solr.DoublePointField" docValues="true" multiValued="true"/>
+
+    <!-- The format for this date field is of the form 1995-12-31T23:59:59Z, and
+         is a more restricted form of the canonical representation of dateTime
+         http://www.w3.org/TR/xmlschema-2/#dateTime
+         The trailing "Z" designates UTC time and is mandatory.
+         Optional fractional seconds are allowed: 1995-12-31T23:59:59.999Z
+         All other components are mandatory.
+
+         Expressions can also be used to denote calculations that should be
+         performed relative to "NOW" to determine the value, ie...
+
+               NOW/HOUR
+                  ... Round to the start of the current hour
+               NOW-1DAY
+                  ... Exactly 1 day prior to now
+               NOW/DAY+6MONTHS+3DAYS
+                  ... 6 months and 3 days in the future from the start of
+                      the current day
+
+      -->
+    <!-- KD-tree versions of date fields -->
+    <fieldType name="pdate" class="solr.DatePointField" docValues="true"/>
+    <fieldType name="pdates" class="solr.DatePointField" docValues="true" multiValued="true"/>
+
+    <!--Binary data type. The data should be sent/retrieved in as Base64 encoded Strings -->
+    <fieldType name="binary" class="solr.BinaryField"/>
+
+    <!-- solr.TextField allows the specification of custom text analyzers
+         specified as a tokenizer and a list of token filters. Different
+         analyzers may be specified for indexing and querying.
+
+         The optional positionIncrementGap puts space between multiple fields of
+         this type on the same document, with the purpose of preventing false phrase
+         matching across fields.
+
+         For more info on customizing your analyzer chain, please see
+         http://lucene.apache.org/solr/guide/understanding-analyzers-tokenizers-and-filters.html#understanding-analyzers-tokenizers-and-filters
+     -->
+
+    <!-- One can also specify an existing Analyzer class that has a
+         default constructor via the class attribute on the analyzer element.
+         Example:
+    <fieldType name="text_greek" class="solr.TextField">
+      <analyzer class="org.apache.lucene.analysis.el.GreekAnalyzer"/>
+    </fieldType>
+    -->
+
+    <!-- A text field that only splits on whitespace for exact matching of words -->
+    <dynamicField name="*_ws" type="text_ws"  indexed="true"  stored="true"/>
+    <fieldType name="text_ws" class="solr.TextField" positionIncrementGap="100">
+      <analyzer>
+        <tokenizer class="solr.WhitespaceTokenizerFactory"/>
+      </analyzer>
+    </fieldType>
+
+    <!-- A general text field that has reasonable, generic
+         cross-language defaults: it tokenizes with StandardTokenizer,
+	       removes stop words from case-insensitive "stopwords.txt"
+	       (empty by default), and down cases.  At query time only, it
+	       also applies synonyms.
+	  -->
+    <fieldType name="text_general" class="solr.TextField" positionIncrementGap="100" multiValued="true">
+      <analyzer type="index">
+        <tokenizer class="solr.StandardTokenizerFactory"/>
+        <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt" />
+        <!-- in this example, we will only use synonyms at query time
+        <filter class="solr.SynonymGraphFilterFactory" synonyms="index_synonyms.txt" ignoreCase="true" expand="false"/>
+        <filter class="solr.FlattenGraphFilterFactory"/>
+        -->
+        <filter class="solr.LowerCaseFilterFactory"/>
+      </analyzer>
+      <analyzer type="query">
+        <tokenizer class="solr.StandardTokenizerFactory"/>
+        <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt" />
+        <filter class="solr.SynonymGraphFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/>
+        <filter class="solr.LowerCaseFilterFactory"/>
+      </analyzer>
+    </fieldType>
+
+    <!-- Just like text_general except it reverses the characters of
+	       each token, to enable more efficient leading wildcard queries.
+    -->
+    <dynamicField name="*_txt_rev" type="text_general_rev"  indexed="true"  stored="true"/>
+    <fieldType name="text_general_rev" class="solr.TextField" positionIncrementGap="100">
+      <analyzer type="index">
+        <tokenizer class="solr.StandardTokenizerFactory"/>
+        <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt" />
+        <filter class="solr.LowerCaseFilterFactory"/>
+        <filter class="solr.ReversedWildcardFilterFactory" withOriginal="true"
+                maxPosAsterisk="3" maxPosQuestion="2" maxFractionAsterisk="0.33"/>
+      </analyzer>
+      <analyzer type="query">
+        <tokenizer class="solr.StandardTokenizerFactory"/>
+        <filter class="solr.SynonymGraphFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/>
+        <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt" />
+        <filter class="solr.LowerCaseFilterFactory"/>
+      </analyzer>
+    </fieldType>
+
+    <dynamicField name="*_phon_en" type="phonetic_en"  indexed="true"  stored="true"/>
+    <fieldType name="phonetic_en" stored="false" indexed="true" class="solr.TextField" >
+      <analyzer>
+        <tokenizer class="solr.StandardTokenizerFactory"/>
+        <filter class="solr.DoubleMetaphoneFilterFactory" inject="false"/>
+      </analyzer>
+    </fieldType>
+
+    <!-- lowercases the entire field value, keeping it as a single token.  -->
+    <dynamicField name="*_s_lower" type="lowercase"  indexed="true"  stored="true"/>
+    <fieldType name="lowercase" class="solr.TextField" positionIncrementGap="100">
+      <analyzer>
+        <tokenizer class="solr.KeywordTokenizerFactory"/>
+        <filter class="solr.LowerCaseFilterFactory" />
+      </analyzer>
+    </fieldType>
+
+    <!--
+      Example of using PathHierarchyTokenizerFactory at index time, so
+      queries for paths match documents at that path, or in descendent paths
+    -->
+    <dynamicField name="*_descendent_path" type="descendent_path"  indexed="true"  stored="true"/>
+    <fieldType name="descendent_path" class="solr.TextField">
+      <analyzer type="index">
+        <tokenizer class="solr.PathHierarchyTokenizerFactory" delimiter="/" />
+      </analyzer>
+      <analyzer type="query">
+        <tokenizer class="solr.KeywordTokenizerFactory" />
+      </analyzer>
+    </fieldType>
+
+    <!--
+      Example of using PathHierarchyTokenizerFactory at query time, so
+      queries for paths match documents at that path, or in ancestor paths
+    -->
+    <dynamicField name="*_ancestor_path" type="ancestor_path"  indexed="true"  stored="true"/>
+    <fieldType name="ancestor_path" class="solr.TextField">
+      <analyzer type="index">
+        <tokenizer class="solr.KeywordTokenizerFactory" />
+      </analyzer>
+      <analyzer type="query">
+        <tokenizer class="solr.PathHierarchyTokenizerFactory" delimiter="/" />
+      </analyzer>
+    </fieldType>
+
+    <!-- This point type indexes the coordinates as separate fields (subFields)
+      If subFieldType is defined, it references a type, and a dynamic field
+      definition is created matching *___<typename>.  Alternately, if
+      subFieldSuffix is defined, that is used to create the subFields.
+      Example: if subFieldType="double", then the coordinates would be
+        indexed in fields myloc_0___double,myloc_1___double.
+      Example: if subFieldSuffix="_d" then the coordinates would be indexed
+        in fields myloc_0_d,myloc_1_d
+      The subFields are an implementation detail of the fieldType, and end
+      users normally should not need to know about them.
+     -->
+    <dynamicField name="*_point" type="point"  indexed="true"  stored="true"/>
+    <fieldType name="point" class="solr.PointType" dimension="2" subFieldSuffix="_d"/>
+
+    <!-- A specialized field for geospatial search filters and distance sorting. -->
+    <fieldType name="location" class="solr.LatLonPointSpatialField" docValues="true"/>
+
+    <!-- A geospatial field type that supports multiValued and polygon shapes.
+      For more information about this and other spatial fields see:
+      http://lucene.apache.org/solr/guide/spatial-search.html
+    -->
+    <fieldType name="location_rpt" class="solr.SpatialRecursivePrefixTreeFieldType"
+               geo="true" distErrPct="0.025" maxDistErr="0.001" distanceUnits="kilometers" />
+
+    <!-- Payloaded field types -->
+    <fieldType name="delimited_payloads_float" stored="false" indexed="true" class="solr.TextField">
+      <analyzer>
+        <tokenizer class="solr.WhitespaceTokenizerFactory"/>
+        <filter class="solr.DelimitedPayloadTokenFilterFactory" encoder="float"/>
+      </analyzer>
+    </fieldType>
+    <fieldType name="delimited_payloads_int" stored="false" indexed="true" class="solr.TextField">
+      <analyzer>
+        <tokenizer class="solr.WhitespaceTokenizerFactory"/>
+        <filter class="solr.DelimitedPayloadTokenFilterFactory" encoder="integer"/>
+      </analyzer>
+    </fieldType>
+    <fieldType name="delimited_payloads_string" stored="false" indexed="true" class="solr.TextField">
+      <analyzer>
+        <tokenizer class="solr.WhitespaceTokenizerFactory"/>
+        <filter class="solr.DelimitedPayloadTokenFilterFactory" encoder="identity"/>
+      </analyzer>
+    </fieldType>
+
+    <!-- Similarity is the scoring routine for each document vs. a query.
+       A custom Similarity or SimilarityFactory may be specified here, but
+       the default is fine for most applications.
+       For more info: http://lucene.apache.org/solr/guide/other-schema-elements.html#OtherSchemaElements-Similarity
+    -->
+    <!--
+     <similarity class="com.example.solr.CustomSimilarityFactory">
+       <str name="paramkey">param value</str>
+     </similarity>
+    -->
+
+</schema>

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/test-files/configsets/collection1/conf/solrconfig.xml
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/src/test-files/configsets/collection1/conf/solrconfig.xml b/solr/contrib/prometheus-exporter/src/test-files/configsets/collection1/conf/solrconfig.xml
new file mode 100644
index 0000000..72c5430
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/src/test-files/configsets/collection1/conf/solrconfig.xml
@@ -0,0 +1,232 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ 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.
+-->
+
+<config>
+
+  <luceneMatchVersion>${tests.luceneMatchVersion:LATEST}</luceneMatchVersion>
+
+  <dataDir>${solr.data.dir:}</dataDir>
+
+  <directoryFactory name="DirectoryFactory"
+                    class="${solr.directoryFactory:solr.NRTCachingDirectoryFactory}"/>
+
+  <codecFactory class="solr.SchemaCodecFactory"/>
+
+  <indexConfig>
+    <lockType>${solr.lock.type:native}</lockType>
+  </indexConfig>
+
+  <jmx />
+
+  <updateHandler class="solr.DirectUpdateHandler2">
+
+    <updateLog>
+      <str name="dir">${solr.ulog.dir:}</str>
+      <int name="numVersionBuckets">${solr.ulog.numVersionBuckets:65536}</int>
+    </updateLog>
+
+    <autoCommit>
+      <maxTime>${solr.autoCommit.maxTime:15000}</maxTime>
+      <openSearcher>false</openSearcher>
+    </autoCommit>
+
+    <autoSoftCommit>
+      <maxTime>${solr.autoSoftCommit.maxTime:-1}</maxTime>
+    </autoSoftCommit>
+
+  </updateHandler>
+
+  <query>
+
+    <maxBooleanClauses>1024</maxBooleanClauses>
+
+    <filterCache class="solr.FastLRUCache"
+                 size="512"
+                 initialSize="512"
+                 autowarmCount="0"/>
+
+    <queryResultCache class="solr.LRUCache"
+                      size="512"
+                      initialSize="512"
+                      autowarmCount="0"/>
+
+    <documentCache class="solr.LRUCache"
+                   size="512"
+                   initialSize="512"
+                   autowarmCount="0"/>
+
+    <cache name="perSegFilter"
+           class="solr.search.LRUCache"
+           size="10"
+           initialSize="0"
+           autowarmCount="10"
+           regenerator="solr.NoOpRegenerator" />
+
+    <enableLazyFieldLoading>true</enableLazyFieldLoading>
+
+    <queryResultWindowSize>20</queryResultWindowSize>
+
+    <queryResultMaxDocsCached>200</queryResultMaxDocsCached>
+
+    <listener event="newSearcher" class="solr.QuerySenderListener">
+      <arr name="queries">
+      </arr>
+    </listener>
+    <listener event="firstSearcher" class="solr.QuerySenderListener">
+      <arr name="queries">
+      </arr>
+    </listener>
+
+    <useColdSearcher>false</useColdSearcher>
+
+  </query>
+
+  <requestDispatcher>
+
+    <httpCaching never304="true" />
+
+  </requestDispatcher>
+
+  <!-- Request Handlers
+
+       http://wiki.apache.org/solr/SolrRequestHandler
+
+       Incoming queries will be dispatched to a specific handler by name
+       based on the path specified in the request.
+
+       If a Request Handler is declared with startup="lazy", then it will
+       not be initialized until the first request that uses it.
+
+    -->
+  <!-- SearchHandler
+
+       http://wiki.apache.org/solr/SearchHandler
+
+       For processing Search Queries, the primary Request Handler
+       provided with Solr is "SearchHandler" It delegates to a sequent
+       of SearchComponents (see below) and supports distributed
+       queries across multiple shards
+    -->
+  <requestHandler name="/select" class="solr.SearchHandler">
+    <lst name="defaults">
+      <str name="echoParams">explicit</str>
+      <int name="rows">10</int>
+    </lst>
+  </requestHandler>
+
+  <!-- Update Processors
+
+       Chains of Update Processor Factories for dealing with Update
+       Requests can be declared, and then used by name in Update
+       Request Processors
+
+       http://wiki.apache.org/solr/UpdateRequestProcessor
+
+    -->
+
+  <!-- Add unknown fields to the schema
+
+       Field type guessing update processors that will
+       attempt to parse string-typed field values as Booleans, Longs,
+       Doubles, or Dates, and then add schema fields with the guessed
+       field types. Text content will be indexed as "text_general" as
+       well as a copy to a plain string version in *_str.
+
+       These require that the schema is both managed and mutable, by
+       declaring schemaFactory as ManagedIndexSchemaFactory, with
+       mutable specified as true.
+
+       See http://wiki.apache.org/solr/GuessingFieldTypes
+    -->
+  <updateProcessor class="solr.UUIDUpdateProcessorFactory" name="uuid"/>
+  <updateProcessor class="solr.RemoveBlankFieldUpdateProcessorFactory" name="remove-blank"/>
+  <updateProcessor class="solr.FieldNameMutatingUpdateProcessorFactory" name="field-name-mutating">
+    <str name="pattern">[^\w-\.]</str>
+    <str name="replacement">_</str>
+  </updateProcessor>
+  <updateProcessor class="solr.ParseBooleanFieldUpdateProcessorFactory" name="parse-boolean"/>
+  <updateProcessor class="solr.ParseLongFieldUpdateProcessorFactory" name="parse-long"/>
+  <updateProcessor class="solr.ParseDoubleFieldUpdateProcessorFactory" name="parse-double"/>
+  <updateProcessor class="solr.ParseDateFieldUpdateProcessorFactory" name="parse-date">
+    <arr name="format">
+      <str>yyyy-MM-dd'T'HH:mm:ss.SSSZ</str>
+      <str>yyyy-MM-dd'T'HH:mm:ss,SSSZ</str>
+      <str>yyyy-MM-dd'T'HH:mm:ss.SSS</str>
+      <str>yyyy-MM-dd'T'HH:mm:ss,SSS</str>
+      <str>yyyy-MM-dd'T'HH:mm:ssZ</str>
+      <str>yyyy-MM-dd'T'HH:mm:ss</str>
+      <str>yyyy-MM-dd'T'HH:mmZ</str>
+      <str>yyyy-MM-dd'T'HH:mm</str>
+      <str>yyyy-MM-dd HH:mm:ss.SSSZ</str>
+      <str>yyyy-MM-dd HH:mm:ss,SSSZ</str>
+      <str>yyyy-MM-dd HH:mm:ss.SSS</str>
+      <str>yyyy-MM-dd HH:mm:ss,SSS</str>
+      <str>yyyy-MM-dd HH:mm:ssZ</str>
+      <str>yyyy-MM-dd HH:mm:ss</str>
+      <str>yyyy-MM-dd HH:mmZ</str>
+      <str>yyyy-MM-dd HH:mm</str>
+      <str>yyyy-MM-dd</str>
+    </arr>
+  </updateProcessor>
+  <updateProcessor class="solr.AddSchemaFieldsUpdateProcessorFactory" name="add-schema-fields">
+    <lst name="typeMapping">
+      <str name="valueClass">java.lang.String</str>
+      <str name="fieldType">text_general</str>
+      <lst name="copyField">
+        <str name="dest">*_str</str>
+        <int name="maxChars">256</int>
+      </lst>
+      <!-- Use as default mapping instead of defaultFieldType -->
+      <bool name="default">true</bool>
+    </lst>
+    <lst name="typeMapping">
+      <str name="valueClass">java.lang.Boolean</str>
+      <str name="fieldType">booleans</str>
+    </lst>
+    <lst name="typeMapping">
+      <str name="valueClass">java.util.Date</str>
+      <str name="fieldType">pdates</str>
+    </lst>
+    <lst name="typeMapping">
+      <str name="valueClass">java.lang.Long</str>
+      <str name="valueClass">java.lang.Integer</str>
+      <str name="fieldType">plongs</str>
+    </lst>
+    <lst name="typeMapping">
+      <str name="valueClass">java.lang.Number</str>
+      <str name="fieldType">pdoubles</str>
+    </lst>
+  </updateProcessor>
+
+  <!-- The update.autoCreateFields property can be turned to false to disable schemaless mode -->
+  <updateRequestProcessorChain name="add-unknown-fields-to-the-schema" default="${update.autoCreateFields:true}"
+           processor="uuid,remove-blank,field-name-mutating,parse-boolean,parse-long,parse-double,parse-date,add-schema-fields">
+    <processor class="solr.LogUpdateProcessorFactory"/>
+    <processor class="solr.DistributedUpdateProcessorFactory"/>
+    <processor class="solr.RunUpdateProcessorFactory"/>
+  </updateRequestProcessorChain>
+
+  <queryResponseWriter name="json" class="solr.JSONResponseWriter">
+    <!-- For the purposes of the tutorial, JSON responses are written as
+     plain text so that they are easy to read in *any* browser.
+     If you expect a MIME type of "application/json" just remove this override.
+    -->
+    <str name="content-type">text/plain; charset=UTF-8</str>
+  </queryResponseWriter>
+
+</config>

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/test-files/configsets/collection1/conf/stopwords.txt
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/src/test-files/configsets/collection1/conf/stopwords.txt b/solr/contrib/prometheus-exporter/src/test-files/configsets/collection1/conf/stopwords.txt
new file mode 100644
index 0000000..ae1e83e
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/src/test-files/configsets/collection1/conf/stopwords.txt
@@ -0,0 +1,14 @@
+# 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.

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/test-files/configsets/collection1/conf/synonyms.txt
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/src/test-files/configsets/collection1/conf/synonyms.txt b/solr/contrib/prometheus-exporter/src/test-files/configsets/collection1/conf/synonyms.txt
new file mode 100644
index 0000000..eab4ee8
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/src/test-files/configsets/collection1/conf/synonyms.txt
@@ -0,0 +1,29 @@
+# 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.
+
+#-----------------------------------------------------------------------
+#some test synonym mappings unlikely to appear in real input text
+aaafoo => aaabar
+bbbfoo => bbbfoo bbbbar
+cccfoo => cccbar cccbaz
+fooaaa,baraaa,bazaaa
+
+# Some synonym groups specific to this example
+GB,gib,gigabyte,gigabytes
+MB,mib,megabyte,megabytes
+Television, Televisions, TV, TVs
+#notice we use "gib" instead of "GiB" so any WordDelimiterGraphFilter coming
+#after us won't split it into two words.
+
+# Synonym mappings can be used for spelling correction too
+pixima => pixma
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/test-files/exampledocs/gb18030-example.xml
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/src/test-files/exampledocs/gb18030-example.xml b/solr/contrib/prometheus-exporter/src/test-files/exampledocs/gb18030-example.xml
new file mode 100644
index 0000000..01743d3
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/src/test-files/exampledocs/gb18030-example.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="GB18030"?>
+<!--
+ 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.
+-->
+
+<add>
+  <doc>
+    <field name="id">GB18030TEST</field>
+    <field name="name">Test with some GB18030 encoded characters</field>
+    <field name="features">No accents here</field>
+    <field name="features">����һ������</field>
+    <field name="features">This is a feature (translated)</field>
+    <field name="features">����ļ��Ǻ��й���</field>
+    <field name="features">This document is very shiny (translated)</field>
+    <field name="price">0.0</field>
+    <field name="inStock">true</field>
+  </doc>
+</add>
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/test-files/exampledocs/hd.xml
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/src/test-files/exampledocs/hd.xml b/solr/contrib/prometheus-exporter/src/test-files/exampledocs/hd.xml
new file mode 100644
index 0000000..9cf7d1b
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/src/test-files/exampledocs/hd.xml
@@ -0,0 +1,56 @@
+<!--
+ 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.
+-->
+
+<add>
+<doc>
+  <field name="id">SP2514N</field>
+  <field name="name">Samsung SpinPoint P120 SP2514N - hard drive - 250 GB - ATA-133</field>
+  <field name="manu">Samsung Electronics Co. Ltd.</field>
+  <!-- Join -->
+  <field name="manu_id_s">samsung</field>
+  <field name="cat">electronics</field>
+  <field name="cat">hard drive</field>
+  <field name="features">7200RPM, 8MB cache, IDE Ultra ATA-133</field>
+  <field name="features">NoiseGuard, SilentSeek technology, Fluid Dynamic Bearing (FDB) motor</field>
+  <field name="price">92.0</field>
+  <field name="popularity">6</field>
+  <field name="inStock">true</field>
+  <field name="manufacturedate_dt">2006-02-13T15:26:37Z</field>
+  <!-- Near Oklahoma city -->
+  <field name="store">35.0752,-97.032</field>
+</doc>
+
+<doc>
+  <field name="id">6H500F0</field>
+  <field name="name">Maxtor DiamondMax 11 - hard drive - 500 GB - SATA-300</field>
+  <field name="manu">Maxtor Corp.</field>
+  <!-- Join -->
+  <field name="manu_id_s">maxtor</field>
+  <field name="cat">electronics</field>
+  <field name="cat">hard drive</field>
+  <field name="features">SATA 3.0Gb/s, NCQ</field>
+  <field name="features">8.5ms seek</field>
+  <field name="features">16MB cache</field>
+  <field name="price">350.0</field>
+  <field name="popularity">6</field>
+  <field name="inStock">true</field>
+  <!-- Buffalo store -->
+  <field name="store">45.17614,-93.87341</field>
+  <field name="manufacturedate_dt">2006-02-13T15:26:37Z</field>
+</doc>
+</add>
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/test-files/exampledocs/ipod_other.xml
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/src/test-files/exampledocs/ipod_other.xml b/solr/contrib/prometheus-exporter/src/test-files/exampledocs/ipod_other.xml
new file mode 100644
index 0000000..3de32f3
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/src/test-files/exampledocs/ipod_other.xml
@@ -0,0 +1,60 @@
+<!--
+ 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.
+-->
+
+<add>
+
+<doc>
+  <field name="id">F8V7067-APL-KIT</field>
+  <field name="name">Belkin Mobile Power Cord for iPod w/ Dock</field>
+  <field name="manu">Belkin</field>
+  <!-- Join -->
+  <field name="manu_id_s">belkin</field>
+  <field name="cat">electronics</field>
+  <field name="cat">connector</field>
+  <field name="features">car power adapter, white</field>
+  <field name="weight">4.0</field>
+  <field name="price">19.95</field>
+  <field name="popularity">1</field>
+  <field name="inStock">false</field>
+  <!-- Buffalo store -->
+  <field name="store">45.18014,-93.87741</field>
+  <field name="manufacturedate_dt">2005-08-01T16:30:25Z</field>
+</doc>
+
+<doc>
+  <field name="id">IW-02</field>
+  <field name="name">iPod &amp; iPod Mini USB 2.0 Cable</field>
+  <field name="manu">Belkin</field>
+  <!-- Join -->
+  <field name="manu_id_s">belkin</field>
+  <field name="cat">electronics</field>
+  <field name="cat">connector</field>
+  <field name="features">car power adapter for iPod, white</field>
+  <field name="weight">2.0</field>
+  <field name="price">11.50</field>
+  <field name="popularity">1</field>
+  <field name="inStock">false</field>
+  <!-- San Francisco store -->
+  <field name="store">37.7752,-122.4232</field>
+  <field name="manufacturedate_dt">2006-02-14T23:55:59Z</field>
+</doc>
+
+
+</add>
+
+
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/test-files/exampledocs/ipod_video.xml
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/src/test-files/exampledocs/ipod_video.xml b/solr/contrib/prometheus-exporter/src/test-files/exampledocs/ipod_video.xml
new file mode 100644
index 0000000..1ca5f6f
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/src/test-files/exampledocs/ipod_video.xml
@@ -0,0 +1,40 @@
+<!--
+ 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.
+-->
+
+<add><doc>
+  <field name="id">MA147LL/A</field>
+  <field name="name">Apple 60 GB iPod with Video Playback Black</field>
+  <field name="manu">Apple Computer Inc.</field>
+  <!-- Join -->
+  <field name="manu_id_s">apple</field>
+  <field name="cat">electronics</field>
+  <field name="cat">music</field>
+  <field name="features">iTunes, Podcasts, Audiobooks</field>
+  <field name="features">Stores up to 15,000 songs, 25,000 photos, or 150 hours of video</field>
+  <field name="features">2.5-inch, 320x240 color TFT LCD display with LED backlight</field>
+  <field name="features">Up to 20 hours of battery life</field>
+  <field name="features">Plays AAC, MP3, WAV, AIFF, Audible, Apple Lossless, H.264 video</field>
+  <field name="features">Notes, Calendar, Phone book, Hold button, Date display, Photo wallet, Built-in games, JPEG photo playback, Upgradeable firmware, USB 2.0 compatibility, Playback speed control, Rechargeable capability, Battery level indication</field>
+  <field name="includes">earbud headphones, USB cable</field>
+  <field name="weight">5.5</field>
+  <field name="price">399.00</field>
+  <field name="popularity">10</field>
+  <field name="inStock">true</field>
+  <!-- Dodge City store -->
+  <field name="store">37.7752,-100.0232</field>
+  <field name="manufacturedate_dt">2005-10-12T08:00:00Z</field>
+</doc></add>

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/test-files/exampledocs/manufacturers.xml
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/src/test-files/exampledocs/manufacturers.xml b/solr/contrib/prometheus-exporter/src/test-files/exampledocs/manufacturers.xml
new file mode 100644
index 0000000..e3121d5
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/src/test-files/exampledocs/manufacturers.xml
@@ -0,0 +1,75 @@
+<!--
+ 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.
+-->
+
+<add>
+  <doc>
+    <field name="id">adata</field>
+    <field name="compName_s">A-Data Technology</field>
+    <field name="address_s">46221 Landing Parkway Fremont, CA 94538</field>
+  </doc>
+  <doc>
+    <field name="id">apple</field>
+    <field name="compName_s">Apple</field>
+    <field name="address_s">1 Infinite Way, Cupertino CA</field>
+  </doc>
+  <doc>
+    <field name="id">asus</field>
+    <field name="compName_s">ASUS Computer</field>
+    <field name="address_s">800 Corporate Way Fremont, CA 94539</field>
+  </doc>
+  <doc>
+    <field name="id">ati</field>
+    <field name="compName_s">ATI Technologies</field>
+    <field name="address_s">33 Commerce Valley Drive East Thornhill, ON L3T 7N6 Canada</field>
+  </doc>
+  <doc>
+    <field name="id">belkin</field>
+    <field name="compName_s">Belkin</field>
+    <field name="address_s">12045 E. Waterfront Drive Playa Vista, CA 90094</field>
+  </doc>
+  <doc>
+    <field name="id">canon</field>
+    <field name="compName_s">Canon, Inc.</field>
+    <field name="address_s">One Canon Plaza Lake Success, NY 11042</field>
+  </doc>
+  <doc>
+    <field name="id">corsair</field>
+    <field name="compName_s">Corsair Microsystems</field>
+    <field name="address_s">46221 Landing Parkway Fremont, CA 94538</field>
+  </doc>
+  <doc>
+    <field name="id">dell</field>
+    <field name="compName_s">Dell, Inc.</field>
+    <field name="address_s">One Dell Way Round Rock, Texas 78682</field>
+  </doc>
+  <doc>
+    <field name="id">maxtor</field>
+    <field name="compName_s">Maxtor Corporation</field>
+    <field name="address_s">920 Disc Drive Scotts Valley, CA 95066</field>
+  </doc>
+  <doc>
+    <field name="id">samsung</field>
+    <field name="compName_s">Samsung Electronics Co. Ltd.</field>
+    <field name="address_s">105 Challenger Rd. Ridgefield Park, NJ 07660-0511</field>
+  </doc>
+  <doc>
+    <field name="id">viewsonic</field>
+    <field name="compName_s">ViewSonic Corp</field>
+    <field name="address_s">381 Brea Canyon Road Walnut, CA 91789-0708</field>
+  </doc>
+</add>
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/test-files/exampledocs/mem.xml
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/src/test-files/exampledocs/mem.xml b/solr/contrib/prometheus-exporter/src/test-files/exampledocs/mem.xml
new file mode 100644
index 0000000..48af522
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/src/test-files/exampledocs/mem.xml
@@ -0,0 +1,77 @@
+<!--
+ 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.
+-->
+
+<add>
+<doc>
+  <field name="id">TWINX2048-3200PRO</field>
+  <field name="name">CORSAIR  XMS 2GB (2 x 1GB) 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) Dual Channel Kit System Memory - Retail</field>
+  <field name="manu">Corsair Microsystems Inc.</field>
+  <!-- Join -->
+  <field name="manu_id_s">corsair</field>
+  <field name="cat">electronics</field>
+  <field name="cat">memory</field>
+  <field name="features">CAS latency 2,  2-3-3-6 timing, 2.75v, unbuffered, heat-spreader</field>
+  <field name="price">185.00</field>
+  <field name="popularity">5</field>
+  <field name="inStock">true</field>
+  <!-- San Francisco store -->
+  <field name="store">37.7752,-122.4232</field>
+  <field name="manufacturedate_dt">2006-02-13T15:26:37Z</field>
+
+  <!-- a field for testing payload tagged text via DelimitedPayloadTokenFilter -->
+  <field name="payloads">electronics|6.0 memory|3.0</field>
+</doc>
+
+<doc>
+  <field name="id">VS1GB400C3</field>
+  <field name="name">CORSAIR ValueSelect 1GB 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) System Memory - Retail</field>
+  <field name="manu">Corsair Microsystems Inc.</field>
+  <!-- Join -->
+  <field name="manu_id_s">corsair</field>
+  <field name="cat">electronics</field>
+  <field name="cat">memory</field>
+  <field name="price">74.99</field>
+  <field name="popularity">7</field>
+  <field name="inStock">true</field>
+  <!-- Dodge City store -->
+  <field name="store">37.7752,-100.0232</field>
+  <field name="manufacturedate_dt">2006-02-13T15:26:37Z</field>
+
+  <field name="payloads">electronics|4.0 memory|2.0</field>
+</doc>
+
+<doc>
+  <field name="id">VDBDB1A16</field>
+  <field name="name">A-DATA V-Series 1GB 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) System Memory - OEM</field>
+  <field name="manu">A-DATA Technology Inc.</field>
+  <!-- Join -->
+  <field name="manu_id_s">corsair</field>
+  <field name="cat">electronics</field>
+  <field name="cat">memory</field>
+  <field name="features">CAS latency 3,   2.7v</field>
+  <!-- note: price & popularity is missing on this one -->
+  <field name="popularity">0</field>
+  <field name="inStock">true</field>
+  <!-- Buffalo store -->
+  <field name="store">45.18414,-93.88141</field>
+  <field name="manufacturedate_dt">2006-02-13T15:26:37Z</field>
+
+  <field name="payloads">electronics|0.9 memory|0.1</field>
+</doc>
+
+</add>
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/test-files/exampledocs/money.xml
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/src/test-files/exampledocs/money.xml b/solr/contrib/prometheus-exporter/src/test-files/exampledocs/money.xml
new file mode 100644
index 0000000..b1b8036
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/src/test-files/exampledocs/money.xml
@@ -0,0 +1,65 @@
+<!--
+ 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.
+-->
+
+<!-- Example documents utilizing the CurrencyField type -->
+<add>
+<doc>
+  <field name="id">USD</field>
+  <field name="name">One Dollar</field>
+  <field name="manu">Bank of America</field>
+  <field name="manu_id_s">boa</field>
+  <field name="cat">currency</field>
+  <field name="features">Coins and notes</field>
+  <field name="price_c">1,USD</field>
+  <field name="inStock">true</field>
+</doc>
+
+<doc>
+  <field name="id">EUR</field>
+  <field name="name">One Euro</field>
+  <field name="manu">European Union</field>
+  <field name="manu_id_s">eu</field>
+  <field name="cat">currency</field>
+  <field name="features">Coins and notes</field>
+  <field name="price_c">1,EUR</field>
+  <field name="inStock">true</field>
+</doc>
+
+<doc>
+  <field name="id">GBP</field>
+  <field name="name">One British Pound</field>
+  <field name="manu">U.K.</field>
+  <field name="manu_id_s">uk</field>
+  <field name="cat">currency</field>
+  <field name="features">Coins and notes</field>
+  <field name="price_c">1,GBP</field>
+  <field name="inStock">true</field>
+</doc>
+
+<doc>
+  <field name="id">NOK</field>
+  <field name="name">One Krone</field>
+  <field name="manu">Bank of Norway</field>
+  <field name="manu_id_s">nor</field>
+  <field name="cat">currency</field>
+  <field name="features">Coins and notes</field>
+  <field name="price_c">1,NOK</field>
+  <field name="inStock">true</field>
+</doc>
+
+</add>
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/test-files/exampledocs/monitor.xml
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/src/test-files/exampledocs/monitor.xml b/solr/contrib/prometheus-exporter/src/test-files/exampledocs/monitor.xml
new file mode 100644
index 0000000..d0343af
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/src/test-files/exampledocs/monitor.xml
@@ -0,0 +1,34 @@
+<!--
+ 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.
+-->
+
+<add><doc>
+  <field name="id">3007WFP</field>
+  <field name="name">Dell Widescreen UltraSharp 3007WFP</field>
+  <field name="manu">Dell, Inc.</field>
+  <!-- Join -->
+  <field name="manu_id_s">dell</field>
+  <field name="cat">electronics and computer1</field>
+  <field name="features">30" TFT active matrix LCD, 2560 x 1600, .25mm dot pitch, 700:1 contrast</field>
+  <field name="includes">USB cable</field>
+  <field name="weight">401.6</field>
+  <field name="price">2199.0</field>
+  <field name="popularity">6</field>
+  <field name="inStock">true</field>
+  <!-- Buffalo store -->
+  <field name="store">43.17614,-90.57341</field>
+</doc></add>
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/test-files/exampledocs/monitor2.xml
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/src/test-files/exampledocs/monitor2.xml b/solr/contrib/prometheus-exporter/src/test-files/exampledocs/monitor2.xml
new file mode 100644
index 0000000..eaf9e22
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/src/test-files/exampledocs/monitor2.xml
@@ -0,0 +1,33 @@
+<!--
+ 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.
+-->
+
+<add><doc>
+  <field name="id">VA902B</field>
+  <field name="name">ViewSonic VA902B - flat panel display - TFT - 19"</field>
+  <field name="manu">ViewSonic Corp.</field>
+  <!-- Join -->
+  <field name="manu_id_s">viewsonic</field>
+  <field name="cat">electronics and stuff2</field>
+  <field name="features">19" TFT active matrix LCD, 8ms response time, 1280 x 1024 native resolution</field>
+  <field name="weight">190.4</field>
+  <field name="price">279.95</field>
+  <field name="popularity">6</field>
+  <field name="inStock">true</field>
+  <!-- Buffalo store -->
+  <field name="store">45.18814,-93.88541</field>
+</doc></add>
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/test-files/exampledocs/mp500.xml
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/src/test-files/exampledocs/mp500.xml b/solr/contrib/prometheus-exporter/src/test-files/exampledocs/mp500.xml
new file mode 100644
index 0000000..a8f51b6
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/src/test-files/exampledocs/mp500.xml
@@ -0,0 +1,43 @@
+<!--
+ 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.
+-->
+
+<add><doc>
+  <field name="id">0579B002</field>
+  <field name="name">Canon PIXMA MP500 All-In-One Photo Printer</field>
+  <field name="manu">Canon Inc.</field>
+  <!-- Join -->
+  <field name="manu_id_s">canon</field>
+  <field name="cat">electronics</field>
+  <field name="cat">multifunction printer</field>
+  <field name="cat">printer</field>
+  <field name="cat">scanner</field>
+  <field name="cat">copier</field>
+  <field name="features">Multifunction ink-jet color photo printer</field>
+  <field name="features">Flatbed scanner, optical scan resolution of 1,200 x 2,400 dpi</field>
+  <field name="features">2.5" color LCD preview screen</field>
+  <field name="features">Duplex Copying</field>
+  <field name="features">Printing speed up to 29ppm black, 19ppm color</field>
+  <field name="features">Hi-Speed USB</field>
+  <field name="features">memory card: CompactFlash, Micro Drive, SmartMedia, Memory Stick, Memory Stick Pro, SD Card, and MultiMediaCard</field>
+  <field name="weight">352.0</field>
+  <field name="price">179.99</field>
+  <field name="popularity">6</field>
+  <field name="inStock">true</field>
+  <!-- Buffalo store -->
+  <field name="store">45.19214,-93.89941</field>
+</doc></add>
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/test-files/exampledocs/sample.html
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/src/test-files/exampledocs/sample.html b/solr/contrib/prometheus-exporter/src/test-files/exampledocs/sample.html
new file mode 100644
index 0000000..656b656
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/src/test-files/exampledocs/sample.html
@@ -0,0 +1,13 @@
+<html>
+<head>
+  <title>Welcome to Solr</title>
+</head>
+<body>
+<p>
+  Here is some text
+</p>
+<p>distinct<br/>words</p>
+<div>Here is some text in a div</div>
+<div>This has a <a href="http://www.apache.org">link</a>.</div>
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/test-files/exampledocs/sd500.xml
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/src/test-files/exampledocs/sd500.xml b/solr/contrib/prometheus-exporter/src/test-files/exampledocs/sd500.xml
new file mode 100644
index 0000000..145c6fd
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/src/test-files/exampledocs/sd500.xml
@@ -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.
+-->
+
+<add><doc>
+  <field name="id">9885A004</field>
+  <field name="name">Canon PowerShot SD500</field>
+  <field name="manu">Canon Inc.</field>
+  <!-- Join -->
+  <field name="manu_id_s">canon</field>
+  <field name="cat">electronics</field>
+  <field name="cat">camera</field>
+  <field name="features">3x zoop, 7.1 megapixel Digital ELPH</field>
+  <field name="features">movie clips up to 640x480 @30 fps</field>
+  <field name="features">2.0" TFT LCD, 118,000 pixels</field>
+  <field name="features">built in flash, red-eye reduction</field>
+  <field name="includes">32MB SD card, USB cable, AV cable, battery</field>
+  <field name="weight">6.4</field>
+  <field name="price">329.95</field>
+  <field name="popularity">7</field>
+  <field name="inStock">true</field>
+  <field name="manufacturedate_dt">2006-02-13T15:26:37Z</field>
+  <!-- Buffalo store -->
+  <field name="store">45.19614,-93.90341</field>
+</doc></add>

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/test-files/exampledocs/solr.xml
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/src/test-files/exampledocs/solr.xml b/solr/contrib/prometheus-exporter/src/test-files/exampledocs/solr.xml
new file mode 100644
index 0000000..a365617
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/src/test-files/exampledocs/solr.xml
@@ -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.
+-->
+
+<add>
+<doc>
+  <field name="id">SOLR1000</field>
+  <field name="name">Solr, the Enterprise Search Server</field>
+  <field name="manu">Apache Software Foundation</field>
+  <field name="cat">software</field>
+  <field name="cat">search</field>
+  <field name="features">Advanced Full-Text Search Capabilities using Lucene</field>
+  <field name="features">Optimized for High Volume Web Traffic</field>
+  <field name="features">Standards Based Open Interfaces - XML and HTTP</field>
+  <field name="features">Comprehensive HTML Administration Interfaces</field>
+  <field name="features">Scalability - Efficient Replication to other Solr Search Servers</field>
+  <field name="features">Flexible and Adaptable with XML configuration and Schema</field>
+  <field name="features">Good unicode support: h&#xE9;llo (hello with an accent over the e)</field>
+  <field name="price">0.0</field>
+  <field name="popularity">10</field>
+  <field name="inStock">true</field>
+  <field name="incubationdate_dt">2006-01-17T00:00:00.000Z</field>
+</doc>
+</add>
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/test-files/exampledocs/utf8-example.xml
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/src/test-files/exampledocs/utf8-example.xml b/solr/contrib/prometheus-exporter/src/test-files/exampledocs/utf8-example.xml
new file mode 100644
index 0000000..ee300a6
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/src/test-files/exampledocs/utf8-example.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+
+<!-- 
+  After posting this to Solr with bin/post, searching for "êâîôû" from
+  the solr/admin/ search page must return this document.
+ -->
+
+<add>
+  <doc>
+    <field name="id">UTF8TEST</field>
+    <field name="name">Test with some UTF-8 encoded characters</field>
+    <field name="manu">Apache Software Foundation</field>
+    <field name="cat">software</field>
+    <field name="cat">search</field>
+    <field name="features">No accents here</field>
+    <field name="features">This is an e acute: é</field>
+    <field name="features">eaiou with circumflexes: êâîôû</field>
+    <field name="features">eaiou with umlauts: ëäïöü</field>
+    <field name="features">tag with escaped chars: &lt;nicetag/&gt;</field>
+    <field name="features">escaped ampersand: Bonnie &amp; Clyde</field>
+    <field name="features">Outside the BMP:𐌈 codepoint=10308, a circle with an x inside. UTF8=f0908c88 UTF16=d800 df08</field>
+    <field name="price">0.0</field>
+    <field name="inStock">true</field>
+  </doc>
+</add>
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/test-files/exampledocs/vidcard.xml
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/src/test-files/exampledocs/vidcard.xml b/solr/contrib/prometheus-exporter/src/test-files/exampledocs/vidcard.xml
new file mode 100644
index 0000000..d867d82
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/src/test-files/exampledocs/vidcard.xml
@@ -0,0 +1,62 @@
+<!--
+ 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.
+-->
+
+<add>
+<doc>
+  <field name="id">EN7800GTX/2DHTV/256M</field>
+  <field name="name">ASUS Extreme N7800GTX/2DHTV (256 MB)</field>
+  <!-- Denormalized -->
+  <field name="manu">ASUS Computer Inc.</field>
+  <!-- Join -->
+  <field name="manu_id_s">asus</field>
+  <field name="cat">electronics</field>
+  <field name="cat">graphics card</field>
+  <field name="features">NVIDIA GeForce 7800 GTX GPU/VPU clocked at 486MHz</field>
+  <field name="features">256MB GDDR3 Memory clocked at 1.35GHz</field>
+  <field name="features">PCI Express x16</field>
+  <field name="features">Dual DVI connectors, HDTV out, video input</field>
+  <field name="features">OpenGL 2.0, DirectX 9.0</field>
+  <field name="weight">16.0</field>
+  <field name="price">479.95</field>
+  <field name="popularity">7</field>
+  <field name="store">40.7143,-74.006</field>
+  <field name="inStock">false</field>
+  <field name="manufacturedate_dt">2006-02-13T15:26:37Z/DAY</field>
+</doc>
+  <!-- yes, you can add more than one document at a time -->
+<doc>
+  <field name="id">100-435805</field>
+  <field name="name">ATI Radeon X1900 XTX 512 MB PCIE Video Card</field>
+  <field name="manu">ATI Technologies</field>
+  <!-- Join -->
+  <field name="manu_id_s">ati</field>
+  <field name="cat">electronics</field>
+  <field name="cat">graphics card</field>
+  <field name="features">ATI RADEON X1900 GPU/VPU clocked at 650MHz</field>
+  <field name="features">512MB GDDR3 SDRAM clocked at 1.55GHz</field>
+  <field name="features">PCI Express x16</field>
+  <field name="features">dual DVI, HDTV, svideo, composite out</field>
+  <field name="features">OpenGL 2.0, DirectX 9.0</field>
+  <field name="weight">48.0</field>
+  <field name="price">649.99</field>
+  <field name="popularity">7</field>
+  <field name="inStock">false</field>
+  <field name="manufacturedate_dt">2006-02-13T15:26:37Z/DAY</field>
+  <!-- NYC store -->
+  <field name="store">40.7143,-74.006</field>
+</doc>
+</add>

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/collector/SolrCollectorTest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/collector/SolrCollectorTest.java b/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/collector/SolrCollectorTest.java
new file mode 100644
index 0000000..9b5ddef
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/collector/SolrCollectorTest.java
@@ -0,0 +1,93 @@
+/*
+ * 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.prometheus.collector;
+
+import org.apache.solr.prometheus.collector.config.SolrCollectorConfig;
+import org.apache.solr.prometheus.exporter.SolrExporter;
+import org.apache.solr.prometheus.exporter.SolrExporterTestBase;
+import io.prometheus.client.CollectorRegistry;
+import org.apache.lucene.util.LuceneTestCase.Slow;
+import org.apache.solr.client.solrj.impl.CloudSolrClient;
+import org.apache.solr.client.solrj.request.ContentStreamUpdateRequest;
+import org.junit.Test;
+import org.yaml.snakeyaml.Yaml;
+
+import java.io.File;
+import java.io.FileReader;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Unit test for SolrCollector.
+ */
+@Slow
+public class SolrCollectorTest extends SolrExporterTestBase {
+  CollectorRegistry registry;
+
+  @Override
+  public void setUp() throws Exception {
+    super.setUp();
+    registry = new CollectorRegistry();
+  }
+
+  @Override
+  public void tearDown() throws Exception {
+    super.tearDown();
+  }
+
+  @Test
+  public void testSolrCollector() throws Exception {
+    String configFile = getFile("conf/config.yml").getAbsolutePath();
+
+    CloudSolrClient cloudSolrClient = cluster.getSolrClient();
+    SolrCollectorConfig collectorConfig = new Yaml().loadAs(new FileReader(configFile), SolrCollectorConfig.class);
+
+    SolrCollector collector = new SolrCollector(cloudSolrClient, collectorConfig, 1);
+
+    assertNotNull(collector);
+  }
+
+  @Test
+  public void testCollect() throws Exception {
+    String configFile = getFile("conf/config.yml").getAbsolutePath();
+
+    CloudSolrClient cloudSolrClient = cluster.getSolrClient();
+    SolrCollectorConfig collectorConfig = new Yaml().loadAs(new FileReader(configFile), SolrCollectorConfig.class);
+
+    SolrCollector collector = new SolrCollector(cloudSolrClient, collectorConfig, 1);
+
+    this.registry.register(collector);
+    this.registry.register(SolrExporter.scrapeErrorTotal);
+
+    // index sample docs
+    File exampleDocsDir = new File(getFile("exampledocs").getAbsolutePath());
+    List<File> xmlFiles = Arrays.asList(exampleDocsDir.listFiles((dir, name) -> name.endsWith(".xml")));
+    for (File xml : xmlFiles) {
+      ContentStreamUpdateRequest req = new ContentStreamUpdateRequest("/update");
+      req.addFile(xml, "application/xml");
+      cloudSolrClient.request(req, "collection1");
+    }
+    cloudSolrClient.commit("collection1");
+
+    // collect metrics
+    collector.collect();
+
+    // check scrape error count
+    assertEquals(0.0, registry.getSampleValue("solr_exporter_scrape_error_total", new String[]{}, new String[]{}), .001);
+  }
+}
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/collector/config/SolrCollectorConfigTest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/collector/config/SolrCollectorConfigTest.java b/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/collector/config/SolrCollectorConfigTest.java
new file mode 100644
index 0000000..a0adfc7
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/collector/config/SolrCollectorConfigTest.java
@@ -0,0 +1,106 @@
+/*
+ * 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.prometheus.collector.config;
+
+import org.apache.solr.prometheus.scraper.config.SolrScraperConfig;
+import org.apache.solr.SolrTestCaseJ4;
+import org.junit.Test;
+import org.yaml.snakeyaml.Yaml;
+
+import java.io.FileReader;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Unit test for SolrCollectorConfig.
+ */
+public class SolrCollectorConfigTest extends SolrTestCaseJ4 {
+  @Test
+  public void testCollectorConfig() throws Exception {
+    String configFile = getFile("conf/config.yml").getAbsolutePath();
+
+    SolrCollectorConfig collectorConfig = new Yaml().loadAs(new FileReader(configFile), SolrCollectorConfig.class);
+
+    assertNotNull(collectorConfig);
+  }
+
+  @Test
+  public void testGetMetricsConfig() throws Exception {
+    String configFile = getFile("conf/config.yml").getAbsolutePath();
+
+    SolrCollectorConfig collectorConfig = new Yaml().loadAs(new FileReader(configFile), SolrCollectorConfig.class);
+
+    assertNotNull(collectorConfig.getMetrics());
+  }
+
+  @Test
+  public void testSetMetricsConfig() throws Exception {
+    String configFile = getFile("conf/config.yml").getAbsolutePath();
+
+    SolrCollectorConfig collectorConfig = new Yaml().loadAs(new FileReader(configFile), SolrCollectorConfig.class);
+
+    SolrScraperConfig metricsConfig = new SolrScraperConfig();
+
+    collectorConfig.setMetrics(metricsConfig);
+
+    assertNotNull(collectorConfig.getMetrics());
+  }
+
+  @Test
+  public void testGetCollectionsConfig() throws Exception {
+    String configFile = getFile("conf/config.yml").getAbsolutePath();
+
+    SolrCollectorConfig collectorConfig = new Yaml().loadAs(new FileReader(configFile), SolrCollectorConfig.class);
+
+    assertNotNull(collectorConfig.getCollections());
+  }
+
+  @Test
+  public void testSetCollectionsConfig() throws Exception {
+    String configFile = getFile("conf/config.yml").getAbsolutePath();
+
+    SolrCollectorConfig collectorConfig = new Yaml().loadAs(new FileReader(configFile), SolrCollectorConfig.class);
+
+    SolrScraperConfig collectionsConfig = new SolrScraperConfig();
+
+    collectorConfig.setCollections(collectionsConfig);
+
+    assertNotNull(collectorConfig.getCollections());
+  }
+
+  @Test
+  public void testGetQueryConfigs() throws Exception {
+    String configFile = getFile("conf/config.yml").getAbsolutePath();
+
+    SolrCollectorConfig collectorConfig = new Yaml().loadAs(new FileReader(configFile), SolrCollectorConfig.class);
+
+    assertNotNull(collectorConfig.getQueries());
+  }
+
+  @Test
+  public void testSetQueryConfigs() throws Exception {
+    String configFile = getFile("conf/config.yml").getAbsolutePath();
+
+    SolrCollectorConfig collectorConfig = new Yaml().loadAs(new FileReader(configFile), SolrCollectorConfig.class);
+
+    List<SolrScraperConfig> queryConfigs = new ArrayList<>();
+
+    collectorConfig.setQueries(queryConfigs);
+
+    assertNotNull(collectorConfig.getQueries());
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/exporter/SolrExporterTest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/exporter/SolrExporterTest.java b/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/exporter/SolrExporterTest.java
new file mode 100644
index 0000000..c8d903b
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/exporter/SolrExporterTest.java
@@ -0,0 +1,106 @@
+/*
+ * 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.prometheus.exporter;
+
+import org.apache.solr.prometheus.collector.config.SolrCollectorConfig;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.lucene.util.LuceneTestCase.Slow;
+import org.apache.solr.client.solrj.impl.CloudSolrClient;
+import org.apache.solr.client.solrj.request.ContentStreamUpdateRequest;
+import org.junit.Test;
+import org.yaml.snakeyaml.Yaml;
+
+import java.io.File;
+import java.io.FileReader;
+import java.net.ServerSocket;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Unit test for SolrExporter.
+ */
+@Slow
+public class SolrExporterTest extends SolrExporterTestBase {
+
+  @Override
+  public void setUp() throws Exception {
+      super.setUp();
+  }
+
+  @Override
+  public void tearDown() throws Exception {
+      super.tearDown();
+  }
+
+  @Test
+  public void testExecute() throws Exception {
+    String configFile = getFile("conf/config.yml").getAbsolutePath();
+
+    SolrCollectorConfig collectorConfig = new Yaml().loadAs(new FileReader(configFile), SolrCollectorConfig.class);
+
+    // solr client
+    CloudSolrClient cloudSolrClient = cluster.getSolrClient();
+
+    int port;
+    ServerSocket socket = null;
+    try {
+      socket = new ServerSocket(0);
+      port = socket.getLocalPort();
+    } finally {
+      socket.close();
+    }
+
+    // index sample docs
+    File exampleDocsDir = new File(getFile("exampledocs").getAbsolutePath());
+    List<File> xmlFiles = Arrays.asList(exampleDocsDir.listFiles((dir, name) -> name.endsWith(".xml")));
+    for (File xml : xmlFiles) {
+      ContentStreamUpdateRequest req = new ContentStreamUpdateRequest("/update");
+      req.addFile(xml, "application/xml");
+      cloudSolrClient.request(req, "collection1");
+    }
+    cloudSolrClient.commit("collection1");
+
+    // start exporter
+    SolrExporter solrExporter = new SolrExporter(port, cloudSolrClient, collectorConfig, 1);
+    try {
+      solrExporter.start();
+
+      URI uri = new URI("http://localhost:" + String.valueOf(port) + "/metrics");
+
+      CloseableHttpClient httpclient = HttpClients.createDefault();
+      CloseableHttpResponse response = null;
+      try {
+        HttpGet request = new HttpGet(uri);
+        response = httpclient.execute(request);
+
+        int expectedHTTPStatusCode = HttpStatus.SC_OK;
+        int actualHTTPStatusCode = response.getStatusLine().getStatusCode();
+        assertEquals(expectedHTTPStatusCode, actualHTTPStatusCode);
+      } finally {
+        response.close();
+        httpclient.close();
+      }
+    } finally {
+      solrExporter.stop();
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/exporter/SolrExporterTestBase.java
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/exporter/SolrExporterTestBase.java b/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/exporter/SolrExporterTestBase.java
new file mode 100644
index 0000000..57ba8e0
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/src/test/org/apache/solr/prometheus/exporter/SolrExporterTestBase.java
@@ -0,0 +1,53 @@
+/*
+ * 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.prometheus.exporter;
+
+import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope;
+import org.apache.solr.client.solrj.request.CollectionAdminRequest;
+import org.apache.solr.cloud.AbstractDistribZkTestBase;
+import org.apache.solr.cloud.SolrCloudTestCase;
+import org.junit.BeforeClass;
+
+/**
+ * Test base class.
+ */
+@ThreadLeakScope(ThreadLeakScope.Scope.NONE)
+public class SolrExporterTestBase extends SolrCloudTestCase {
+  public static String COLLECTION = "collection1";
+  public static String CONF_NAME = COLLECTION + "_config";
+  public static String CONF_DIR = getFile("configsets/" + COLLECTION + "/conf").getAbsolutePath();
+  public static int NUM_SHARDS = 2;
+  public static int NUM_REPLICAS = 2;
+  public static int MAX_SHARDS_PER_NODE = 1;
+  public static int NUM_NODES = (NUM_SHARDS * NUM_REPLICAS + (MAX_SHARDS_PER_NODE - 1)) / MAX_SHARDS_PER_NODE;
+  public static int TIMEOUT = 60;
+
+  @BeforeClass
+  public static void setupCluster() throws Exception {
+    configureCluster(NUM_NODES)
+        .addConfig(CONF_NAME, getFile(CONF_DIR).toPath())
+        .configure();
+
+    CollectionAdminRequest
+        .createCollection(COLLECTION, CONF_NAME, NUM_SHARDS, NUM_REPLICAS)
+        .setMaxShardsPerNode(MAX_SHARDS_PER_NODE)
+        .process(cluster.getSolrClient());
+
+    AbstractDistribZkTestBase
+        .waitForRecoveriesToFinish(COLLECTION, cluster.getSolrClient().getZkStateReader(), true, true, TIMEOUT);
+  }
+}


[6/7] lucene-solr:master: SOLR-11795: Add Solr metrics exporter for Prometheus

Posted by ko...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/conf/config.yml
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/conf/config.yml b/solr/contrib/prometheus-exporter/conf/config.yml
new file mode 100644
index 0000000..1661012
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/conf/config.yml
@@ -0,0 +1,1840 @@
+#
+# 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.
+#
+
+ping:
+  query:
+    path: /admin/ping
+  jsonQueries:
+    - |-
+      . as $object | $object |
+      (if $object.status == "OK" then 1.0 else 0.0 end) as $value |
+      {
+        name         : "solr_ping",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/ping.html",
+        label_names  : [],
+        label_values : [],
+        value        : $value
+      }
+
+metrics:
+  query:
+    path: /admin/metrics
+    params:
+      - group: 'all'
+      - type: 'all'
+      - prefix: ''
+      - property: ''
+  jsonQueries:
+    ##############################
+    # jetty
+    ##############################
+    # solr_metrics_jetty_response_total
+    - |-
+      .metrics["solr.jetty"] | to_entries | .[] | select(.key | startswith("org.eclipse.jetty.server.handler.DefaultHandler")) | select(.key | endswith("xx-responses")) as $object |
+      $object.key | split(".") | last | split("-") | first as $status |
+      $object.value.count as $value |
+      {
+        name         : "solr_metrics_jetty_response_total",
+        type         : "COUNTER",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["status"],
+        label_values : [$status],
+        value        : $value
+      }
+
+    # solr_metrics_jetty_requests_total
+    - |-
+      .metrics["solr.jetty"] | to_entries | .[] | select(.key | startswith("org.eclipse.jetty.server.handler.DefaultHandler.")) | select(.key | endswith("-requests")) | select (.value | type == "object") as $object |
+      $object.key | split(".") | last | split("-") | first as $method |
+      $object.value.count as $value |
+      {
+        name         : "solr_metrics_jetty_requests_total",
+        type         : "COUNTER",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["method"],
+        label_values : [$method],
+        value        : $value
+      }
+
+    # solr_metrics_jetty_dispatches_total
+    - |-
+      .metrics["solr.jetty"] | to_entries | .[] | select(.key == "org.eclipse.jetty.server.handler.DefaultHandler.dispatches") as $object |
+      $object.value.count as $value |
+      {
+        name         : "solr_metrics_jetty_dispatches_total",
+        type         : "COUNTER",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : [],
+        label_values : [],
+        value        : $value
+      }
+
+    ##############################
+    # jvm
+    ##############################
+    # solr_metrics_jvm_buffers
+    - |-
+      .metrics["solr.jvm"] | to_entries | .[] | select(.key | startswith("buffers.")) | select(.key | endswith(".Count")) as $object |
+      $object.key | split(".")[1] as $pool |
+      $object.value as $value |
+      {
+        name         : "solr_metrics_jvm_buffers",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["pool"],
+        label_values : [$pool],
+        value        : $value
+      }
+
+    # solr_metrics_jvm_buffers_bytes
+    - |-
+      .metrics["solr.jvm"] | to_entries | .[] | select(.key | startswith("buffers.")) | select(.key | (endswith(".MemoryUsed") or endswith(".TotalCapacity"))) as $object |
+      $object.key | split(".")[1] as $pool |
+      $object.key | split(".") | last as $item |
+      $object.value as $value |
+      {
+        name         : "solr_metrics_jvm_buffers_bytes",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["pool", "item"],
+        label_values : [$pool, $item],
+        value        : $value
+      }
+
+    # solr_metrics_jvm_gc_total
+    - |-
+      .metrics["solr.jvm"] | to_entries | .[] | select(.key | startswith("gc.")) | select(.key | endswith(".count")) as $object |
+      $object.key | split(".")[1] as $item |
+      $object.value as $value |
+      {
+        name         : "solr_metrics_jvm_gc_total",
+        type         : "COUNTER",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["item"],
+        label_values : [$item],
+        value        : $value
+      }
+
+    # solr_metrics_jvm_gc_seconds_total
+    - |-
+      .metrics["solr.jvm"] | to_entries | .[] | select(.key | startswith("gc.")) | select(.key | endswith(".time")) as $object |
+      $object.key | split(".")[1] as $item |
+      ($object.value / 1000) as $value |
+      {
+        name         : "solr_metrics_jvm_gc_seconds_total",
+        type         : "COUNTER",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["item"],
+        label_values : [$item],
+        value        : $value
+      }
+
+    # solr_metrics_jvm_memory_heap_bytes
+    - |-
+      .metrics["solr.jvm"] | to_entries | .[] | select(.key | startswith("memory.heap.")) | select(.key | endswith(".usage") | not) as $object |
+      $object.key | split(".") | last as $item |
+      $object.value as $value |
+      {
+        name         : "solr_metrics_jvm_memory_heap_bytes",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["item"],
+        label_values : [$item],
+        value        : $value
+      }
+
+    # solr_metrics_jvm_memory_non_heap_bytes
+    - |-
+      .metrics["solr.jvm"] | to_entries | .[] | select(.key | startswith("memory.non-heap.")) | select(.key | endswith(".usage") | not) as $object |
+      $object.key | split(".") | last as $item |
+      $object.value as $value |
+      {
+        name         : "solr_metrics_jvm_memory_non_heap_bytes",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["item"],
+        label_values : [$item],
+        value        : $value
+      }
+
+    # solr_metrics_jvm_memory_pools_bytes
+    - |-
+      .metrics["solr.jvm"] | to_entries | .[] | select(.key | startswith("memory.pools.")) | select(.key | endswith(".usage") | not) as $object |
+      $object.key | split(".")[2] as $space |
+      $object.key | split(".") | last as $item |
+      $object.value as $value |
+      {
+        name         : "solr_metrics_jvm_memory_pools_bytes",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["space", "item"],
+        label_values : [$space, $item],
+        value        : $value
+      }
+
+    # solr_metrics_jvm_memory_bytes
+    - |-
+      .metrics["solr.jvm"] | to_entries | .[] | select(.key | startswith("memory.total.")) as $object |
+      $object.key | split(".") | last as $item |
+      $object.value as $value |
+      {
+        name         : "solr_metrics_jvm_memory_bytes",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["item"],
+        label_values : [$item],
+        value        : $value
+      }
+
+    # solr_metrics_jvm_os_memory_bytes
+    - |-
+      .metrics["solr.jvm"] | to_entries | .[] | select(.key == "os.committedVirtualMemorySize" or .key == "os.freePhysicalMemorySize" or .key == "os.freeSwapSpaceSize" or .key =="os.totalPhysicalMemorySize" or .key == "os.totalSwapSpaceSize") as $object |
+      $object.key | split(".") | last as $item |
+      $object.value as $value |
+      {
+        name         : "solr_metrics_jvm_os_memory_bytes",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["item"],
+        label_values : [$item],
+        value        : $value
+      }
+
+    # solr_metrics_jvm_os_file_descriptors
+    - |-
+      .metrics["solr.jvm"] | to_entries | .[] | select(.key == "os.maxFileDescriptorCount" or .key == "os.openFileDescriptorCount") as $object |
+      $object.key | split(".") | last as $item |
+      $object.value as $value |
+      {
+        name         : "solr_metrics_jvm_os_file_descriptors",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["item"],
+        label_values : [$item],
+        value        : $value
+      }
+
+    # solr_metrics_jvm_os_cpu_load
+    - |-
+      .metrics["solr.jvm"] | to_entries | .[] | select(.key == "os.processCpuLoad" or .key == "os.systemCpuLoad") as $object |
+      $object.key | split(".") | last as $item |
+      $object.value as $value |
+      {
+        name         : "solr_metrics_jvm_os_cpu_load",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["item"],
+        label_values : [$item],
+        value        : $value
+      }
+
+    # solr_metrics_jvm_os_cpu_time_seconds
+    - |-
+      .metrics["solr.jvm"] | to_entries | .[] | select(.key == "os.processCpuTime") as $object |
+      ($object.value / 1000.0) as $value |
+      {
+        name         : "solr_metrics_jvm_os_cpu_time_seconds",
+        type         : "COUNTER",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["item"],
+        label_values : ["processCpuTime"],
+        value        : $value
+      }
+
+    # solr_metrics_jvm_os_load_average
+    - |-
+      .metrics["solr.jvm"] | to_entries | .[] | select(.key == "os.systemLoadAverage") as $object |
+      $object.value as $value |
+      {
+        name         : "solr_metrics_jvm_os_load_average",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["item"],
+        label_values : ["systemLoadAverage"],
+        value        : $value
+      }
+
+    # solr_metrics_jvm_threads
+    - |-
+      .metrics["solr.jvm"] | to_entries | .[] | select(.key | startswith("threads.")) | select(.key | endswith(".count")) as $object |
+      $object.key | split(".")[1] as $item |
+      $object.value as $value |
+      {
+        name         : "solr_metrics_jvm_threads",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["item"],
+        label_values : [$item],
+        value        : $value
+      }
+
+    # solr_metrics_node_client_errors_total
+    - |-
+      .metrics["solr.node"] | to_entries | .[] | select(.key | endswith(".clientErrors")) as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value.count as $value |
+      {
+        name         : "solr_metrics_node_client_errors_total",
+        type         : "COUNTER",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["category", "handler"],
+        label_values : [$category, $handler],
+        value        : $value
+      }
+
+    # solr_metrics_node_errors_total
+    - |-
+      .metrics["solr.node"] | to_entries | .[] | select(.key | endswith(".clientErrors")) as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value.count as $value |
+      {
+        name         : "solr_metrics_node_errors_total",
+        type         : "COUNTER",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["category", "handler"],
+        label_values : [$category, $handler],
+        value        : $value
+      }
+
+    # solr_metrics_node_requests_total
+    - |-
+      .metrics["solr.node"] | to_entries | .[] | select(.key | endswith(".requestTimes")) as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value.count as $value |
+      {
+        name         : "solr_metrics_node_requests_total",
+        type         : "COUNTER",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["category", "handler"],
+        label_values : [$category, $handler],
+        value        : $value
+      }
+
+    # solr_metrics_node_server_errors_total
+    - |-
+      .metrics["solr.node"] | to_entries | .[] | select(.key | endswith(".serverErrors")) as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value.count as $value |
+      {
+        name         : "solr_metrics_node_server_errors_total",
+        type         : "COUNTER",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["category", "handler"],
+        label_values : [$category, $handler],
+        value        : $value
+      }
+
+    # solr_metrics_node_timeouts_total
+    - |-
+      .metrics["solr.node"] | to_entries | .[] | select(.key | endswith(".timeouts")) as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value.count as $value |
+      {
+        name         : "solr_metrics_node_timeouts_total",
+        type         : "COUNTER",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["category", "handler"],
+        label_values : [$category, $handler],
+        value        : $value
+      }
+
+    # solr_metrics_node_time_seconds_total
+    - |-
+      .metrics["solr.node"] | to_entries | .[] | select(.key | endswith(".totalTime")) as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      ($object.value / 1000) as $value |
+      {
+        name         : "solr_metrics_node_time_seconds_total",
+        type         : "COUNTER",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["category", "handler"],
+        label_values : [$category, $handler],
+        value        : $value
+      }
+
+    # solr_metrics_node_cores
+    - |-
+      .metrics["solr.node"] | to_entries | .[] | select(.key | startswith("CONTAINER.cores.")) as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[2] as $item |
+      $object.value as $value |
+      {
+        name         : "solr_metrics_node_cores",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["category", "item"],
+        label_values : [$category, $item],
+        value        : $value
+      }
+
+    # solr_metrics_node_core_root_fs_bytes
+    - |-
+      .metrics["solr.node"] | to_entries | .[] | select(.key | startswith("CONTAINER.fs.coreRoot.")) | select(.key | endswith(".totalSpace") or endswith(".usableSpace")) as $object |
+      $object.key | split(".") as $key_items |
+      $key_items | length as $label_len |
+      $key_items[0] as $category |
+      $key_items[3] as $item |
+      $object.value as $value |
+      {
+        name         : "solr_metrics_node_core_root_fs_bytes",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["category", "item"],
+        label_values : [$category, $item],
+        value        : $value
+      }
+
+    # solr_metrics_node_thread_pool_completed_total
+    - |-
+      .metrics["solr.node"] | to_entries | .[] | select(.key | contains(".threadPool.")) | select(.key | endswith(".completed")) as $object |
+      $object.key | split(".") as $key_items |
+      $key_items | length as $label_len |
+      $key_items[0] as $category |
+      (if $label_len >= 5 then $key_items[1] else "" end) as $handler |
+      (if $label_len >= 5 then $key_items[3] else $key_items[2] end) as $executor |
+      $object.value.count as $value |
+      {
+        name         : "solr_metrics_node_thread_pool_completed_total",
+        type         : "COUNTER",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["category", "handler", "executor"],
+        label_values : [$category, $handler, $executor],
+        value        : $value
+      }
+
+    # solr_metrics_node_thread_pool_running
+    - |-
+      .metrics["solr.node"] | to_entries | .[] | select(.key | contains(".threadPool.")) | select(.key | endswith(".running")) as $object |
+      $object.key | split(".") as $key_items |
+      $key_items | length as $label_len |
+      $key_items[0] as $category |
+      (if $label_len >= 5 then $key_items[1] else "" end) as $handler |
+      (if $label_len >= 5 then $key_items[3] else $key_items[2] end) as $executor |
+      $object.value as $value |
+      {
+        name         : "solr_metrics_node_thread_pool_running",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["category", "handler", "executor"],
+        label_values : [$category, $handler, $executor],
+        value        : $value
+      }
+
+    # solr_metrics_node_thread_pool_submitted_total
+    - |-
+      .metrics["solr.node"] | to_entries | .[] | select(.key | contains(".threadPool.")) | select(.key | endswith(".submitted")) as $object |
+      $object.key | split(".") as $key_items |
+      $key_items | length as $label_len |
+      $key_items[0] as $category |
+      (if $label_len >= 5 then $key_items[1] else "" end) as $handler |
+      (if $label_len >= 5 then $key_items[3] else $key_items[2] end) as $executor |
+      $object.value.count as $value |
+      {
+        name         : "solr_metrics_node_thread_pool_submitted_total",
+        type         : "COUNTER",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["category", "handler", "executor"],
+        label_values : [$category, $handler, $executor],
+        value        : $value
+      }
+
+    # solr_metrics_node_connections
+    - |-
+      .metrics["solr.node"] | to_entries | .[] | select(.key | endswith("Connections")) as $object |
+      $object.key | split(".") as $key_items |
+      $key_items | length as $label_len |
+      $key_items[0] as $category |
+      $key_items[1] as $handler |
+      $key_items[2] as $item |
+      $object.value as $value |
+      {
+        name         : "solr_metrics_node_connections",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["category", "handler", "item"],
+        label_values : [$category, $handler, $item],
+        value        : $value
+      }
+
+    ##############################
+    # core
+    ##############################
+    # solr_metrics_core_client_errors_total
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key | endswith(".clientErrors")) as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      select($handler | startswith("/")) |
+      $object.value.count as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_client_errors_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_client_errors_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_errors_total
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key | endswith(".errors")) | select (.value | type == "object") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      select($handler | startswith("/")) |
+      $object.value.count as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_errors_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_errors_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_requests_total
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key | endswith(".requestTimes")) | select (.value | type == "object") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      select($handler | startswith("/")) |
+      $object.value.count as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_requests_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_requests_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_server_errors_total
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key | endswith(".serverErrors")) | select (.value | type == "object") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      select($handler | startswith("/")) |
+      $object.value.count as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_server_errors_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_server_errors_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_timeouts_total
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key | endswith(".timeouts")) | select (.value | type == "object") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      select($handler | startswith("/")) |
+      $object.value.count as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_timeouts_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_timeouts_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_time_seconds_total
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key | endswith(".totalTime")) as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      select($handler | startswith("/")) |
+      ($object.value / 1000) as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_time_seconds_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_time_seconds_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_field_cache_total
+    - |-
+      .metrics | to_entries | .[] | select (.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "CACHE.core.fieldCache") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.value.entries_count as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_field_cache_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "core"],
+        label_values: [$category, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_field_cache_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "core", "collection", "shard", "replica"],
+        label_values: [$category, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_searcher_cache
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key | startswith("CACHE.searcher.")) | select (.key | endswith("documentCache") or endswith("fieldValueCache") or endswith("filterCache") or endswith("perSegFilter") or endswith("queryResultCache")) as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[2] as $type |
+      $object.value | to_entries | .[] | select(.key == "lookups" or .key == "hits" or .key == "size" or .key == "evictions" or .key == "inserts") as $target |
+      $target.key as $item |
+      $target.value as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_searcher_cache",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "core", "type", "item"],
+        label_values: [$category, $core, $type, $item],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_searcher_cache",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "core", "collection", "shard", "replica", "type", "item"],
+        label_values: [$category, $core, $collection, $shard, $replica, $type, $item],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_searcher_cache_ratio
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key | startswith("CACHE.searcher.")) | select (.key | endswith("documentCache") or endswith("fieldValueCache") or endswith("filterCache") or endswith("perSegFilter") or endswith("queryResultCache")) as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[2] as $type |
+      $object.value | to_entries | .[] | select(.key == "hitratio") as $target |
+      $target.key as $item |
+      $target.value as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_searcher_cache_ratio",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "core", "type", "item"],
+        label_values: [$category, $core, $type, $item],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_searcher_cache_ratio",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "core", "collection", "shard", "replica", "type", "item"],
+        label_values: [$category, $core, $collection, $shard, $replica, $type, $item],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_searcher_warmup_time_seconds
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key | startswith("CACHE.searcher.")) | select (.key | endswith("documentCache") or endswith("fieldValueCache") or endswith("filterCache") or endswith("perSegFilter") or endswith("queryResultCache")) as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[2] as $type |
+      $object.value | to_entries | .[] | select(.key == "warmupTime") as $target |
+      $target.key as $item |
+      ($target.value / 1000) as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_searcher_warmup_time_seconds",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "core", "type", "item"],
+        label_values: [$category, $core, $type, $item],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_searcher_warmup_time_seconds",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "core", "collection", "shard", "replica", "type", "item"],
+        label_values: [$category, $core, $collection, $shard, $replica, $type, $item],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_searcher_cumulative_cache_total
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key | startswith("CACHE.searcher.")) | select (.key | endswith("documentCache") or endswith("fieldValueCache") or endswith("filterCache") or endswith("perSegFilter") or endswith("queryResultCache")) as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[2] as $type |
+      $object.value | to_entries | .[] | select(.key == "cumulative_lookups" or .key == "cumulative_hits" or .key == "cumulative_evictions" or .key == "cumulative_inserts") as $target |
+      $target.key as $item |
+      $target.value as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_searcher_cumulative_cache_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "core", "type", "item"],
+        label_values: [$category, $core, $type, $item],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_searcher_cumulative_cache_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "core", "collection", "shard", "replica", "type", "item"],
+        label_values: [$category, $core, $collection, $shard, $replica, $type, $item],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_searcher_cumulative_cache_ratio
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key | startswith("CACHE.searcher.")) | select (.key | endswith("documentCache") or endswith("fieldValueCache") or endswith("filterCache") or endswith("perSegFilter") or endswith("queryResultCache")) as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[2] as $type |
+      $object.value | to_entries | .[] | select(.key == "cumulative_hitratio") as $target |
+      $target.key as $item |
+      $target.value as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_searcher_cumulative_cache_ratio",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "core", "type", "item"],
+        label_values: [$category, $core, $type, $item],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_searcher_cumulative_cache_ratio",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "core", "collection", "shard", "replica", "type", "item"],
+        label_values: [$category, $core, $collection, $shard, $replica, $type, $item],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_fs_bytes
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key | startswith("CORE.fs.")) | select (.key | endswith(".totalSpace") or endswith(".usableSpace")) as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[2] as $item |
+      $object.value as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_fs_bytes",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "core", "item"],
+        label_values: [$category, $core, $item],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_fs_bytes",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "core", "collection", "shard", "replica", "item"],
+        label_values: [$category, $core, $collection, $shard, $replica, $item],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_highlighter_request_total
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key | startswith("HIGHLIGHTER.")) | select (.key | endswith(".requests")) as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $name |
+      $object.key | split(".")[2] as $item |
+      $object.value as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_highlighter_request_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "core", "name", "item"],
+        label_values: [$category, $core, $name, $item],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_highlighter_request_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "core", "collection", "shard", "replica", "name", "item"],
+        label_values: [$category, $core, $collection, $shard, $replica, $name, $item],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_index_size_bytes
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "INDEX.sizeInBytes") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.value as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_index_size_bytes",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "core"],
+        label_values: [$category, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_index_size_bytes",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "core", "collection", "shard", "replica"],
+        label_values: [$category, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_replication_master
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "REPLICATION./replication.isMaster") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      (if $object.value == true then 1.0 else 0.0 end) as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_replication_master",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_replication_master",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_replication_slave
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "REPLICATION./replication.isSlave") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      (if $object.value == true then 1.0 else 0.0 end) as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_replication_slave",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_replication_slave",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_searcher_documents
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "SEARCHER.searcher.deletedDocs" or .key == "SEARCHER.searcher.maxDoc" or .key == "SEARCHER.searcher.numDocs") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[2] as $item |
+      $object.value as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_searcher_documents",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "core", "item"],
+        label_values: [$category, $core, $item],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_searcher_documents",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "core", "collection", "shard", "replica", "item"],
+        label_values: [$category, $core, $collection, $shard, $replica, $item],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_update_handler_adds
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "UPDATE.updateHandler.adds") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_update_handler_adds",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_update_handler_adds",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_update_handler_auto_commits_total
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "UPDATE.updateHandler.autoCommits") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_update_handler_auto_commits_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_update_handler_auto_commits_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_update_handler_commits_total
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "UPDATE.updateHandler.commits") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value.count as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_update_handler_commits_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_update_handler_commits_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_update_handler_adds_total
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "UPDATE.updateHandler.cumulativeAdds") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value.count as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_update_handler_adds_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_update_handler_adds_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_update_handler_deletes_by_id_total
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "UPDATE.updateHandler.cumulativeDeletesById") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value.count as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_update_handler_deletes_by_id_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_update_handler_deletes_by_id_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_update_handler_deletes_by_query_total
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "UPDATE.updateHandler.cumulativeDeletesByQuery") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value.count as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_update_handler_deletes_by_query_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_update_handler_deletes_by_query_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_update_handler_errors_total
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "UPDATE.updateHandler.cumulativeErrors") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value.count as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_update_handler_errors_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_update_handler_errors_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_update_handler_deletes_by_id
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "UPDATE.updateHandler.deletesById") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_update_handler_deletes_by_id",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_update_handler_deletes_by_id",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_update_handler_deletes_by_query
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "UPDATE.updateHandler.deletesByQuery") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_update_handler_deletes_by_query",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_update_handler_deletes_by_query",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_update_handler_pending_docs
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "UPDATE.updateHandler.docsPending") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_update_handler_pending_docs",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_update_handler_pending_docs",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_update_handler_errors
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "UPDATE.updateHandler.errors") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_update_handler_errors",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_update_handler_errors",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_update_handler_expunge_deletes_total
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "UPDATE.updateHandler.expungeDeletes") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value.count as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_update_handler_expunge_deletes_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_update_handler_expunge_deletes_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_update_handler_merges_total
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "UPDATE.updateHandler.merges") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value.count as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_update_handler_merges_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_update_handler_merges_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_update_handler_optimizes_total
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "UPDATE.updateHandler.optimizes") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value.count as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_update_handler_optimizes_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_update_handler_optimizes_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_update_handler_rollbacks_total
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "UPDATE.updateHandler.rollbacks") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value.count as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_update_handler_rollbacks_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_update_handler_rollbacks_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_update_handler_soft_auto_commits_total
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "UPDATE.updateHandler.softAutoCommits") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_update_handler_soft_auto_commits_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_update_handler_soft_auto_commits_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_update_handler_splits_total
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "UPDATE.updateHandler.splits") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value.count as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_update_handler_splits_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_update_handler_splits_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+
+collections:
+  query:
+    path: /admin/collections
+    params:
+      - action: 'CLUSTERSTATUS'
+  jsonQueries:
+    # solr_collections_live_nodes
+    - |-
+      .cluster.live_nodes | length as $value|
+      {
+        name         : "solr_collections_live_nodes",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/collections-api.html#clusterstatus",
+        label_names  : [],
+        label_values : [],
+        value        : $value
+      }
+
+    # solr_collections_pull_replicas
+    - |-
+      .cluster.collections | to_entries | .[] | . as $object |
+      $object.key as $collection |
+      $object.value.pullReplicas | tonumber as $value |
+      {
+        name         : "solr_collections_pull_replicas",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/collections-api.html#clusterstatus",
+        label_names  : ["collection"],
+        label_values : [$collection],
+        value        : $value
+      }
+
+    # solr_collections_nrt_replicas
+    - |-
+      .cluster.collections | to_entries | .[] | . as $object |
+      $object.key as $collection |
+      $object.value.nrtReplicas | tonumber as $value |
+      {
+        name         : "solr_collections_nrt_replicas",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/collections-api.html#clusterstatus",
+        label_names  : ["collection"],
+        label_values : [$collection],
+        value        : $value
+      }
+
+    # solr_collections_tlog_replicas
+    - |-
+      .cluster.collections | to_entries | .[] | . as $object |
+      $object.key as $collection |
+      $object.value.tlogReplicas | tonumber as $value |
+      {
+        name         : "solr_collections_tlog_replicas",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/collections-api.html#clusterstatus",
+        label_names  : ["collection"],
+        label_values : [$collection],
+        value        : $value
+      }
+
+    # solr_collections_shard_state
+    - |-
+      .cluster.collections | to_entries | .[] | . as $object |
+      $object.key as $collection |
+      $object.value.shards | to_entries | .[] | . as $shard_obj |
+      $shard_obj.key as $shard |
+      (if $shard_obj.value.state == "active" then 1.0 else 0.0 end) as $value |
+      {
+        name         : "solr_collections_shard_state",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/collections-api.html#clusterstatus",
+        label_names  : ["collection","shard"],
+        label_values : [$collection,$shard],
+        value        : $value
+      }
+
+    # solr_collections_replica_state
+    - |-
+      .cluster.collections | to_entries | .[] | . as $object |
+      $object.key as $collection |
+      $object.value.shards | to_entries | .[] | . as $shard_obj |
+      $shard_obj.key as $shard |
+      $shard_obj.value.replicas | to_entries | .[] | . as $replica_obj |
+      $replica_obj.key as $replica_name |
+      $replica_obj.value.core as $core |
+      $core[$collection + "_" + $shard + "_" | length:] as $replica |
+      $replica_obj.value.base_url as $base_url |
+      $replica_obj.value.node_name as $node_name |
+      $replica_obj.value.type as $type |
+      (if $replica_obj.value.state == "active" then 1.0 else 0.0 end) as $value |
+      {
+        name         : "solr_collections_replica_state",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/collections-api.html#clusterstatus",
+        label_names  : ["collection", "shard", "replica", "replica_name", "core", "base_url", "node_name", "type"],
+        label_values : [$collection, $shard, $replica, $replica_name, $core, $base_url, $node_name, $type],
+        value        : $value
+      }
+
+    # solr_collections_shard_leader
+    - |-
+      .cluster.collections | to_entries | .[] | . as $object |
+      $object.key as $collection |
+      $object.value.shards | to_entries | .[] | . as $shard_obj |
+      $shard_obj.key as $shard |
+      $shard_obj.value.replicas | to_entries | .[] | . as $replica_ob

<TRUNCATED>

[7/7] lucene-solr:master: SOLR-11795: Add Solr metrics exporter for Prometheus

Posted by ko...@apache.org.
SOLR-11795: Add Solr metrics exporter for Prometheus


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

Branch: refs/heads/master
Commit: 4bfcbc5c605e2823c924dbe287a67b37d2dd0ca8
Parents: dfc0fe8
Author: koji <ko...@apache.org>
Authored: Tue Feb 20 17:46:47 2018 +0900
Committer: koji <ko...@apache.org>
Committed: Tue Feb 20 17:46:47 2018 +0900

----------------------------------------------------------------------
 solr/CHANGES.txt                                |    2 +
 solr/build.xml                                  |    6 +-
 solr/contrib/prometheus-exporter/README.md      |   21 +
 solr/contrib/prometheus-exporter/README.txt     |    1 +
 .../prometheus-exporter/bin/solr-exporter       |  114 +
 .../prometheus-exporter/bin/solr-exporter.cmd   |  105 +
 solr/contrib/prometheus-exporter/build.xml      |   30 +
 .../contrib/prometheus-exporter/conf/config.yml | 1840 ++++++++
 .../conf/grafana-solr-dashboard.json            | 4465 ++++++++++++++++++
 .../prometheus-exporter/conf/log4j.properties   |   22 +
 solr/contrib/prometheus-exporter/ivy.xml        |   41 +
 .../prometheus/collector/SolrCollector.java     |  402 ++
 .../collector/config/SolrCollectorConfig.java   |   64 +
 .../solr/prometheus/exporter/SolrExporter.java  |  254 +
 .../solr/prometheus/scraper/SolrScraper.java    |  218 +
 .../scraper/config/SolrQueryConfig.java         |   99 +
 .../scraper/config/SolrScraperConfig.java       |   60 +
 .../prometheus-exporter/src/java/overview.html  |   21 +
 .../src/test-files/conf/config.yml              | 1840 ++++++++
 .../src/test-files/conf/log4j.properties        |   22 +
 .../configsets/collection1/conf/managed-schema  |  412 ++
 .../configsets/collection1/conf/solrconfig.xml  |  232 +
 .../configsets/collection1/conf/stopwords.txt   |   14 +
 .../configsets/collection1/conf/synonyms.txt    |   29 +
 .../test-files/exampledocs/gb18030-example.xml  |   32 +
 .../src/test-files/exampledocs/hd.xml           |   56 +
 .../src/test-files/exampledocs/ipod_other.xml   |   60 +
 .../src/test-files/exampledocs/ipod_video.xml   |   40 +
 .../test-files/exampledocs/manufacturers.xml    |   75 +
 .../src/test-files/exampledocs/mem.xml          |   77 +
 .../src/test-files/exampledocs/money.xml        |   65 +
 .../src/test-files/exampledocs/monitor.xml      |   34 +
 .../src/test-files/exampledocs/monitor2.xml     |   33 +
 .../src/test-files/exampledocs/mp500.xml        |   43 +
 .../src/test-files/exampledocs/sample.html      |   13 +
 .../src/test-files/exampledocs/sd500.xml        |   38 +
 .../src/test-files/exampledocs/solr.xml         |   38 +
 .../src/test-files/exampledocs/utf8-example.xml |   42 +
 .../src/test-files/exampledocs/vidcard.xml      |   62 +
 .../prometheus/collector/SolrCollectorTest.java |   93 +
 .../config/SolrCollectorConfigTest.java         |  106 +
 .../prometheus/exporter/SolrExporterTest.java   |  106 +
 .../exporter/SolrExporterTestBase.java          |   53 +
 .../scraper/config/SolrQueryConfigTest.java     |  121 +
 .../scraper/config/SolrScraperConfigTest.java   |   86 +
 .../grafana-solr-dashboard.png                  |  Bin 0 -> 808611 bytes
 .../solr-exporter-diagram.png                   |  Bin 0 -> 29070 bytes
 ...toring-solr-with-prometheus-and-grafana.adoc |  250 +
 solr/solr-ref-guide/src/monitoring-solr.adoc    |    4 +-
 49 files changed, 11837 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/CHANGES.txt
----------------------------------------------------------------------
diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index a4ccdf3..dca7e81 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -168,6 +168,8 @@ New Features
 
 * SOLR-11588: Add matrixMult Stream Evaluator to support matrix multiplication (Joel Bernstein)
 
+* SOLR-11795: Add Solr metrics exporter for Prometheus (Minoru Osuka via koji)
+
 Bug Fixes
 ----------------------
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/build.xml
----------------------------------------------------------------------
diff --git a/solr/build.xml b/solr/build.xml
index 400c711..3f0596f 100644
--- a/solr/build.xml
+++ b/solr/build.xml
@@ -571,19 +571,19 @@
       <tarfileset dir="."
                   prefix="${fullnamever}"
                   includes="LICENSE.txt NOTICE.txt CHANGES.txt README.txt SYSTEM_REQUIREMENTS.txt
-                            bin/** server/** example/** contrib/**/lib/** contrib/**/README.txt 
+                            bin/** server/** example/** contrib/**/lib/** contrib/**/conf/** contrib/**/README.txt
                             licenses/**"
                   excludes="licenses/README.committers.txt **/data/ **/logs/* 
                             **/classes/ **/*.sh **/ivy.xml **/build.xml
                             **/bin/ **/*.iml **/*.ipr **/*.iws **/pom.xml 
-                            **/*pom.xml.template server/etc/test/" />
+                            **/*pom.xml.template server/etc/test/ contrib/**/src/" />
       <tarfileset dir="${dest}/contrib-lucene-libs-to-package"
                   prefix="${fullnamever}"
                   includes="**" />
       <tarfileset dir="."
                   filemode="755"
                   prefix="${fullnamever}"
-                  includes="bin/** server/**/*.sh example/**/*.sh example/**/bin/"
+                  includes="bin/** server/**/*.sh example/**/*.sh example/**/bin/ contrib/**/bin/**"
                   excludes="server/etc/test/**" />
       <tarfileset dir="."
                   prefix="${fullnamever}"

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/README.md
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/README.md b/solr/contrib/prometheus-exporter/README.md
new file mode 100644
index 0000000..888f237
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/README.md
@@ -0,0 +1,21 @@
+Welcome to Apache Solr Prometheus Exporter
+========
+
+Apache Solr Prometheus Exporter (solr-exporter) provides a way for you to expose metrics for Solr to Prometheus.
+
+# Getting Started With Solr Prometheus Exporter
+
+For information on how to get started with solr-exporter please see:
+ * [Solr Reference Guide's section on Monitoring Solr with Prometheus and Grafana](https://lucene.apache.org/solr/guide/monitoring-solr-with-prometheus-and-grafana.html)
+
+# Getting Started With Solr
+
+For information on how to get started with solr please see:
+ * [solr/README.txt](../../README.txt)
+ * [Solr Tutorial](https://lucene.apache.org/solr/guide/solr-tutorial.html)
+
+# How To Contribute
+
+For information on how to contribute see:
+ * http://wiki.apache.org/lucene-java/HowToContribute
+ * http://wiki.apache.org/solr/HowToContribute

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/README.txt
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/README.txt b/solr/contrib/prometheus-exporter/README.txt
new file mode 100644
index 0000000..42061c0
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/README.txt
@@ -0,0 +1 @@
+README.md
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/bin/solr-exporter
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/bin/solr-exporter b/solr/contrib/prometheus-exporter/bin/solr-exporter
new file mode 100644
index 0000000..d69d00b
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/bin/solr-exporter
@@ -0,0 +1,114 @@
+#!/bin/sh
+
+#
+# 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.
+#
+
+BASEDIR=`dirname $0`/..
+BASEDIR=`(cd "$BASEDIR"; pwd)`
+
+# OS specific support.  $var _must_ be set to either true or false.
+cygwin=false;
+darwin=false;
+case "`uname`" in
+  CYGWIN*) cygwin=true ;;
+  Darwin*) darwin=true
+           if [ -z "$JAVA_VERSION" ] ; then
+             JAVA_VERSION="CurrentJDK"
+           else
+             echo "Using Java version: $JAVA_VERSION"
+           fi
+           if [ -z "$JAVA_HOME" ] ; then
+             JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/${JAVA_VERSION}/Home
+           fi
+           ;;
+esac
+
+if [ -z "$JAVA_HOME" ] ; then
+  if [ -r /etc/gentoo-release ] ; then
+    JAVA_HOME=`java-config --jre-home`
+  fi
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin ; then
+  [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+  [ -n "$CLASSPATH" ] && CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
+fi
+
+# If a specific java binary isn't specified search for the standard 'java' binary
+if [ -z "$JAVACMD" ] ; then
+  if [ -n "$JAVA_HOME"  ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+      # IBM's JDK on AIX uses strange locations for the executables
+      JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+      JAVACMD="$JAVA_HOME/bin/java"
+    fi
+  else
+    JAVACMD=`which java`
+  fi
+fi
+
+if [ ! -x "$JAVACMD" ] ; then
+  echo "Error: JAVA_HOME is not defined correctly."
+  echo "  We cannot execute $JAVACMD"
+  exit 1
+fi
+
+if [ -z "$REPO" ]
+then
+  REPO="$BASEDIR"/lib
+fi
+
+CLASSPATH=$CLASSPATH_PREFIX
+for JAR in $(find "$REPO" -name '*.jar')
+do
+  CLASSPATH="$CLASSPATH":"$JAR"
+done
+for JAR in $(find "$BASEDIR"/../../dist/solrj-lib -name '*.jar')
+do
+  CLASSPATH="$CLASSPATH":"$JAR"
+done
+for JAR in $(find "$BASEDIR"/../../dist -name 'solr-solrj-*.jar')
+do
+  CLASSPATH="$CLASSPATH":"$JAR"
+done
+for JAR in $(find "$BASEDIR"/../../dist -name 'solr-prometheus-exporter-*.jar')
+do
+  CLASSPATH="$CLASSPATH":"$JAR"
+done
+
+EXTRA_JVM_ARGUMENTS="-Xmx512m -Dlog4j.configuration=file:"$BASEDIR"/conf/log4j.properties"
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin; then
+  [ -n "$CLASSPATH" ] && CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
+  [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
+  [ -n "$HOME" ] && HOME=`cygpath --path --windows "$HOME"`
+  [ -n "$BASEDIR" ] && BASEDIR=`cygpath --path --windows "$BASEDIR"`
+  [ -n "$REPO" ] && REPO=`cygpath --path --windows "$REPO"`
+fi
+
+exec "$JAVACMD" $JAVA_OPTS \
+  $EXTRA_JVM_ARGUMENTS \
+  -classpath "$CLASSPATH" \
+  -Dapp.name="solr-exporter" \
+  -Dapp.pid="$$" \
+  -Dapp.repo="$REPO" \
+  -Dbasedir="$BASEDIR" \
+  org.apache.solr.prometheus.exporter.SolrExporter \
+  "$@"

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/bin/solr-exporter.cmd
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/bin/solr-exporter.cmd b/solr/contrib/prometheus-exporter/bin/solr-exporter.cmd
new file mode 100644
index 0000000..a09463b
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/bin/solr-exporter.cmd
@@ -0,0 +1,105 @@
+@REM
+@REM Licensed to the Apache Software Foundation (ASF) under one or more
+@REM contributor license agreements.  See the NOTICE file distributed with
+@REM this work for additional information regarding copyright ownership.
+@REM The ASF licenses this file to You under the Apache License, Version 2.0
+@REM (the "License"); you may not use this file except in compliance with
+@REM the License.  You may obtain a copy of the License at
+@REM
+@REM     http://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing, software
+@REM distributed under the License is distributed on an "AS IS" BASIS,
+@REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@REM See the License for the specific language governing permissions and
+@REM limitations under the License.
+@REM
+
+@echo off
+
+set ERROR_CODE=0
+
+:init
+@REM Decide how to startup depending on the version of windows
+
+@REM -- Win98ME
+if NOT "%OS%"=="Windows_NT" goto Win9xArg
+
+@REM set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" @setlocal
+
+@REM -- 4NT shell
+if "%eval[2+2]" == "4" goto 4NTArgs
+
+@REM -- Regular WinNT shell
+set CMD_LINE_ARGS=%*
+goto WinNTGetScriptDir
+
+@REM The 4NT Shell from jp software
+:4NTArgs
+set CMD_LINE_ARGS=%$
+goto WinNTGetScriptDir
+
+:Win9xArg
+@REM Slurp the command line arguments.  This loop allows for an unlimited number
+@REM of agruments (up to the command line limit, anyway).
+set CMD_LINE_ARGS=
+:Win9xApp
+if %1a==a goto Win9xGetScriptDir
+set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1
+shift
+goto Win9xApp
+
+:Win9xGetScriptDir
+set SAVEDIR=%CD%
+%0\
+cd %0\..\.. 
+set BASEDIR=%CD%
+cd %SAVEDIR%
+set SAVE_DIR=
+goto repoSetup
+
+:WinNTGetScriptDir
+set BASEDIR=%~dp0\..
+
+:repoSetup
+
+
+if "%JAVACMD%"=="" set JAVACMD=java
+
+if "%REPO%"=="" set REPO=%BASEDIR%\lib
+
+set CLASSPATH="%CLASSPATH%";"%REPO%\*;%BASEDIR%\..\..\dist\solrj-lib\*;%BASEDIR%\..\..\dist\solr-solrj-*;%BASEDIR%\..\..\dist\solr-prometheus-exporter-*"
+set EXTRA_JVM_ARGUMENTS=-Xmx512m -Dlog4j.configuration=file:%BASEDIR%/conf/log4j.properties
+goto endInit
+
+@REM Reaching here means variables are defined and arguments have been captured
+:endInit
+
+%JAVACMD% %JAVA_OPTS% %EXTRA_JVM_ARGUMENTS% -classpath %CLASSPATH_PREFIX%;%CLASSPATH% -Dapp.name="solr-exporter" -Dapp.repo="%REPO%" -Dbasedir="%BASEDIR%" com.github.mosuka.solr.prometheus.exporter.SolrExporter %CMD_LINE_ARGS%
+if ERRORLEVEL 1 goto error
+goto end
+
+:error
+if "%OS%"=="Windows_NT" @endlocal
+set ERROR_CODE=1
+
+:end
+@REM set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" goto endNT
+
+@REM For old DOS remove the set variables from ENV - we assume they were not set
+@REM before we started - at least we don't leave any baggage around
+set CMD_LINE_ARGS=
+goto postExec
+
+:endNT
+@endlocal
+
+:postExec
+
+if "%FORCE_EXIT_ON_ERROR%" == "on" (
+  if %ERROR_CODE% NEQ 0 exit %ERROR_CODE%
+)
+
+exit /B %ERROR_CODE%

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/build.xml
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/build.xml b/solr/contrib/prometheus-exporter/build.xml
new file mode 100644
index 0000000..ff11769
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/build.xml
@@ -0,0 +1,30 @@
+<?xml version="1.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.
+ -->
+
+<project name="solr-prometheus-exporter" default="default">
+
+  <description>
+    Prometheus exporter for exposing metrics from Solr using Metrics API and Search API.
+  </description>
+
+  <import file="../contrib-build.xml"/>
+
+  <target name="compile-core" depends="solr-contrib-build.compile-core"/>
+  <target name="compile-test" depends="common-solr.compile-test"/>
+</project>


[4/7] lucene-solr:master: SOLR-11795: Add Solr metrics exporter for Prometheus

Posted by ko...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/conf/log4j.properties
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/conf/log4j.properties b/solr/contrib/prometheus-exporter/conf/log4j.properties
new file mode 100644
index 0000000..5dd6899
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/conf/log4j.properties
@@ -0,0 +1,22 @@
+#
+# 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.
+#
+
+log4j.rootLogger=INFO, stdout
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.Target=System.out
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd'T'HH:mm:ss.SSS} %-5p [%c] - %m%n

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/ivy.xml
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/ivy.xml b/solr/contrib/prometheus-exporter/ivy.xml
new file mode 100644
index 0000000..a6d0705
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/ivy.xml
@@ -0,0 +1,41 @@
+<!--
+   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.    
+-->
+<ivy-module version="2.0">
+  <info organisation="org.apache.solr" module="prometheus"/>
+  <configurations defaultconfmapping="compile->master;test->master">
+    <conf name="compile" transitive="false"/>
+    <conf name="test" transitive="false"/>
+  </configurations>
+  <dependencies>
+    <dependency org="io.prometheus" name="simpleclient" rev="0.0.26" conf="compile"/>
+    <dependency org="io.prometheus" name="simpleclient_common" rev="0.0.26" conf="compile"/>
+    <dependency org="io.prometheus" name="simpleclient_httpserver" rev="0.0.26" conf="compile"/>
+    <dependency org="org.yaml" name="snakeyaml" rev="1.16" conf="compile"/>
+    <dependency org="com.fasterxml.jackson.core" name="jackson-core" rev="2.9.1" conf="compile"/>
+    <dependency org="com.fasterxml.jackson.core" name="jackson-databind" rev="2.9.1" conf="compile"/>
+    <dependency org="com.fasterxml.jackson.core" name="jackson-annotations" rev="2.9.1" conf="compile"/>
+    <dependency org="net.thisptr" name="jackson-jq" rev="0.0.8" conf="compile"/>
+    <dependency org="net.sourceforge.argparse4j" name="argparse4j" rev="0.7.0" conf="compile"/>
+    <dependency org="org.slf4j" name="slf4j-api" rev="1.7.25" conf="compile"/>
+    <dependency org="org.slf4j" name="slf4j-log4j12" rev="1.7.25" conf="compile"/>
+    <dependency org="log4j" name="log4j" rev="1.2.17" conf="compile"/>
+
+    <exclude org="*" ext="*" matcher="regexp" type="${ivy.exclude.types}"/>
+  </dependencies>
+</ivy-module>

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/java/org/apache/solr/prometheus/collector/SolrCollector.java
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/src/java/org/apache/solr/prometheus/collector/SolrCollector.java b/solr/contrib/prometheus-exporter/src/java/org/apache/solr/prometheus/collector/SolrCollector.java
new file mode 100644
index 0000000..9341fa2
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/src/java/org/apache/solr/prometheus/collector/SolrCollector.java
@@ -0,0 +1,402 @@
+/*
+ * 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.prometheus.collector;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.solr.prometheus.collector.config.SolrCollectorConfig;
+import org.apache.solr.prometheus.scraper.SolrScraper;
+import org.apache.solr.prometheus.scraper.config.SolrScraperConfig;
+import io.prometheus.client.Collector;
+import org.apache.solr.client.solrj.SolrClient;
+import org.apache.solr.client.solrj.SolrServerException;
+import org.apache.solr.client.solrj.impl.CloudSolrClient;
+import org.apache.solr.client.solrj.impl.HttpSolrClient;
+import org.apache.solr.client.solrj.impl.NoOpResponseParser;
+import org.apache.solr.client.solrj.request.CollectionAdminRequest;
+import org.apache.solr.client.solrj.request.CoreAdminRequest;
+import org.apache.solr.common.params.CoreAdminParams;
+import org.apache.solr.common.util.NamedList;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * SolrCollector
+ */
+public class SolrCollector extends Collector implements Collector.Describable {
+  private static final Logger logger = LoggerFactory.getLogger(SolrCollector.class);
+
+  private SolrClient solrClient;
+  private SolrCollectorConfig config = new SolrCollectorConfig();
+  private int numThreads;
+
+  private static ObjectMapper om = new ObjectMapper();
+
+  /**
+   * Constructor.
+   */
+  public SolrCollector(SolrClient solrClient, SolrCollectorConfig config, int numThreads) {
+    this.solrClient = solrClient;
+    this.config = config;
+    this.numThreads = numThreads;
+  }
+
+  /**
+   * Describe scrape status.
+   */
+  public List<Collector.MetricFamilySamples> describe() {
+    List<MetricFamilySamples> metricFamilies = new ArrayList<>();
+    metricFamilies.add(new MetricFamilySamples("solr_exporter_duration_seconds", Type.GAUGE, "Time this Solr scrape took, in seconds.", new ArrayList<>()));
+    return metricFamilies;
+  }
+
+  /**
+   * Collect samples.
+   */
+  public List<MetricFamilySamples> collect() {
+    // start time of scraping.
+    long startTime = System.nanoTime();
+
+    Map<String, MetricFamilySamples> metricFamilySamplesMap = new LinkedHashMap<>();
+
+    ExecutorService executorService = Executors.newFixedThreadPool(numThreads);
+    List<Future<Map<String, MetricFamilySamples>>> futureList = new ArrayList<>();
+
+    try {
+      // Ping
+      if (config.getPing() != null) {
+        if (solrClient instanceof CloudSolrClient) {
+          List<HttpSolrClient> httpSolrClients = new ArrayList<>();
+          try {
+            httpSolrClients = getHttpSolrClients((CloudSolrClient) solrClient);
+            for (HttpSolrClient httpSolrClient : httpSolrClients) {
+              try {
+                List<String> cores = getCores(httpSolrClient);
+                for (String core : cores) {
+                  SolrScraperConfig pingConfig;
+                  try {
+                    pingConfig = config.getPing().clone();
+                  } catch (CloneNotSupportedException e) {
+                    logger.error(e.getMessage());
+                    continue;
+                  }
+
+                  pingConfig.getQuery().setCore(core);
+
+                  SolrScraper scraper = new SolrScraper(httpSolrClient, pingConfig, Arrays.asList("zk_host"), Arrays.asList(((CloudSolrClient) solrClient).getZkHost()));
+                  Future<Map<String, MetricFamilySamples>> future = executorService.submit(scraper);
+                  futureList.add(future);
+                }
+              } catch (SolrServerException | IOException e) {
+                logger.error(e.getMessage());
+              }
+            }
+
+            // get future
+            for (Future<Map<String, MetricFamilySamples>> future : futureList) {
+              try {
+                Map<String, MetricFamilySamples> m = future.get(60, TimeUnit.SECONDS);
+                mergeMetrics(metricFamilySamplesMap, m);
+              } catch (InterruptedException | ExecutionException | TimeoutException e) {
+                logger.error(e.getMessage());
+              }
+            }
+          } catch (SolrServerException | IOException e) {
+            logger.error(e.getMessage());
+          } finally {
+            for (HttpSolrClient httpSolrClient : httpSolrClients) {
+              try {
+                httpSolrClient.close();
+              } catch (IOException e) {
+                logger.error(e.getMessage());
+              }
+            }
+          }
+
+          try {
+            List<String> collections = getCollections((CloudSolrClient) solrClient);
+            for (String collection : collections) {
+              SolrScraperConfig pingConfig;
+              try {
+                pingConfig = config.getPing().clone();
+              } catch (CloneNotSupportedException e) {
+                logger.error(e.getMessage());
+                continue;
+              }
+
+              pingConfig.getQuery().setCollection(collection);
+              LinkedHashMap<String, String> distrib = new LinkedHashMap<>();
+              distrib.put("distrib", "true");
+              pingConfig.getQuery().setParams(Collections.singletonList(distrib));
+
+              SolrScraper scraper = new SolrScraper(solrClient, pingConfig);
+              Future<Map<String, MetricFamilySamples>> future = executorService.submit(scraper);
+              futureList.add(future);
+            }
+          } catch (SolrServerException | IOException e) {
+            logger.error(e.getMessage());
+          }
+        } else {
+          try {
+            List<String> cores = getCores((HttpSolrClient) solrClient);
+            for (String core : cores) {
+              SolrScraperConfig pingConfig = new SolrScraperConfig();
+              pingConfig.setQuery(config.getPing().getQuery());
+              pingConfig.getQuery().setCore(core);
+
+              pingConfig.setJsonQueries(config.getPing().getJsonQueries());
+
+              SolrScraper scraper = new SolrScraper(solrClient, pingConfig);
+              Future<Map<String, MetricFamilySamples>> future = executorService.submit(scraper);
+              futureList.add(future);
+            }
+          } catch (SolrServerException | IOException e) {
+            logger.error(e.getMessage());
+          }
+        }
+      }
+
+      // Metrics
+      if (config.getMetrics() != null) {
+        if (solrClient instanceof CloudSolrClient) {
+          List<HttpSolrClient> httpSolrClients = new ArrayList<>();
+          try {
+            httpSolrClients = getHttpSolrClients((CloudSolrClient) solrClient);
+            for (HttpSolrClient httpSolrClient : httpSolrClients) {
+              SolrScraper scraper = new SolrScraper(httpSolrClient, config.getMetrics(), Arrays.asList("zk_host"), Arrays.asList(((CloudSolrClient) solrClient).getZkHost()));
+              Future<Map<String, MetricFamilySamples>> future = executorService.submit(scraper);
+              futureList.add(future);
+            }
+
+            // get future
+            for (Future<Map<String, MetricFamilySamples>> future : futureList) {
+              try {
+                Map<String, MetricFamilySamples> m = future.get(60, TimeUnit.SECONDS);
+                mergeMetrics(metricFamilySamplesMap, m);
+              } catch (InterruptedException | ExecutionException | TimeoutException e) {
+                logger.error(e.getMessage());
+              }
+            }
+          } catch (SolrServerException | IOException e) {
+            logger.error(e.getMessage());
+          } finally {
+            for (HttpSolrClient httpSolrClient : httpSolrClients) {
+              try {
+                httpSolrClient.close();
+              } catch (IOException e) {
+                logger.error(e.getMessage());
+              }
+            }
+          }
+        } else {
+          SolrScraper scraper = new SolrScraper(solrClient, config.getMetrics());
+          Future<Map<String, MetricFamilySamples>> future = executorService.submit(scraper);
+          futureList.add(future);
+        }
+      }
+
+      // Collections
+      if (config.getCollections() != null) {
+        if (solrClient instanceof CloudSolrClient) {
+          SolrScraper scraper = new SolrScraper(solrClient, config.getCollections());
+          Future<Map<String, MetricFamilySamples>> future = executorService.submit(scraper);
+          futureList.add(future);
+        }
+      }
+
+      // Query
+      if (config.getQueries() != null) {
+        for (SolrScraperConfig c : config.getQueries()) {
+          SolrScraper scraper = new SolrScraper(solrClient, c);
+          Future<Map<String, MetricFamilySamples>> future = executorService.submit(scraper);
+          futureList.add(future);
+        }
+      }
+
+      // get future
+      for (Future<Map<String, MetricFamilySamples>> future : futureList) {
+        try {
+          Map<String, MetricFamilySamples> m = future.get(60, TimeUnit.SECONDS);
+          mergeMetrics(metricFamilySamplesMap, m);
+        } catch (InterruptedException | ExecutionException | TimeoutException e) {
+          logger.error(e.getMessage());
+        }
+      }
+    } finally {
+      executorService.shutdown();
+    }
+
+    // return value
+    List<MetricFamilySamples> metricFamiliesSamplesList = new ArrayList<>();
+
+    // add solr metrics
+    for (String gaugeMetricName : metricFamilySamplesMap.keySet()) {
+      MetricFamilySamples metricFamilySamples = metricFamilySamplesMap.get(gaugeMetricName);
+      if (metricFamilySamples.samples.size() > 0) {
+        metricFamiliesSamplesList.add(metricFamilySamples);
+      }
+    }
+
+    // add scrape duration metric
+    List<MetricFamilySamples.Sample> durationSample = new ArrayList<>();
+    durationSample.add(new MetricFamilySamples.Sample("solr_exporter_duration_seconds", new ArrayList<>(), new ArrayList<>(), (System.nanoTime() - startTime) / 1.0E9));
+    metricFamiliesSamplesList.add(new MetricFamilySamples("solr_exporter_duration_seconds", Type.GAUGE, "Time this Solr exporter took, in seconds.", durationSample));
+
+    return metricFamiliesSamplesList;
+  }
+
+  /**
+   * Merge metrics.
+   */
+  private Map<String, MetricFamilySamples> mergeMetrics(Map<String, MetricFamilySamples> metrics1, Map<String, MetricFamilySamples> metrics2) {
+    // marge MetricFamilySamples
+    for (String k : metrics2.keySet()) {
+      if (metrics1.containsKey(k)) {
+        for (MetricFamilySamples.Sample sample : metrics2.get(k).samples) {
+          if (!metrics1.get(k).samples.contains(sample)) {
+            metrics1.get(k).samples.add(sample);
+          }
+        }
+      } else {
+        metrics1.put(k, metrics2.get(k));
+      }
+    }
+
+    return metrics1;
+  }
+
+
+  /**
+   * Get target cores via CoreAdminAPI.
+   */
+  public static List<String> getCores(HttpSolrClient httpSolrClient) throws SolrServerException, IOException {
+    List<String> cores = new ArrayList<>();
+
+    NoOpResponseParser responseParser = new NoOpResponseParser();
+    responseParser.setWriterType("json");
+
+    httpSolrClient.setParser(responseParser);
+
+    CoreAdminRequest coreAdminRequest = new CoreAdminRequest();
+    coreAdminRequest.setAction(CoreAdminParams.CoreAdminAction.STATUS);
+    coreAdminRequest.setIndexInfoNeeded(false);
+
+    NamedList<Object> coreAdminResponse = httpSolrClient.request(coreAdminRequest);
+
+    JsonNode statusJsonNode = om.readTree((String) coreAdminResponse.get("response")).get("status");
+
+    for (Iterator<JsonNode> i = statusJsonNode.iterator(); i.hasNext(); ) {
+      String core = i.next().get("name").textValue();
+      if (!cores.contains(core)) {
+        cores.add(core);
+      }
+    }
+
+    return cores;
+  }
+
+  /**
+   * Get target cores via CollectionsAPI.
+   */
+  public static List<String> getCollections(CloudSolrClient cloudSolrClient) throws SolrServerException, IOException {
+    List<String> collections = new ArrayList<>();
+
+    NoOpResponseParser responseParser = new NoOpResponseParser();
+    responseParser.setWriterType("json");
+
+    cloudSolrClient.setParser(responseParser);
+
+    CollectionAdminRequest collectionAdminRequest = new CollectionAdminRequest.List();
+
+    NamedList<Object> collectionAdminResponse = cloudSolrClient.request(collectionAdminRequest);
+
+    JsonNode collectionsJsonNode = om.readTree((String) collectionAdminResponse.get("response")).get("collections");
+
+    for (Iterator<JsonNode> i = collectionsJsonNode.iterator(); i.hasNext(); ) {
+      String collection = i.next().textValue();
+      if (!collections.contains(collection)) {
+        collections.add(collection);
+      }
+    }
+
+    return collections;
+  }
+
+  /**
+   * Get base urls via CollectionsAPI.
+   */
+  private List<String> getBaseUrls(CloudSolrClient cloudSolrClient) throws SolrServerException, IOException {
+    List<String> baseUrls = new ArrayList<>();
+
+    NoOpResponseParser responseParser = new NoOpResponseParser();
+    responseParser.setWriterType("json");
+
+    cloudSolrClient.setParser(responseParser);
+
+    CollectionAdminRequest collectionAdminRequest = new CollectionAdminRequest.ClusterStatus();
+
+    NamedList<Object> collectionAdminResponse = cloudSolrClient.request(collectionAdminRequest);
+
+    List<JsonNode> baseUrlJsonNode = om.readTree((String) collectionAdminResponse.get("response")).findValues("base_url");
+
+    for (Iterator<JsonNode> i = baseUrlJsonNode.iterator(); i.hasNext(); ) {
+      String baseUrl = i.next().textValue();
+      if (!baseUrls.contains(baseUrl)) {
+        baseUrls.add(baseUrl);
+      }
+    }
+
+    return baseUrls;
+  }
+
+  /**
+   * Get HTTP Solr Clients
+   */
+  private List<HttpSolrClient> getHttpSolrClients(CloudSolrClient cloudSolrClient) throws SolrServerException, IOException {
+    List<HttpSolrClient> solrClients = new ArrayList<>();
+
+    for (String baseUrl : getBaseUrls(cloudSolrClient)) {
+      NoOpResponseParser responseParser = new NoOpResponseParser();
+      responseParser.setWriterType("json");
+
+      HttpSolrClient.Builder builder = new HttpSolrClient.Builder();
+      builder.withBaseSolrUrl(baseUrl);
+
+      HttpSolrClient httpSolrClient = builder.build();
+      httpSolrClient.setParser(responseParser);
+
+      solrClients.add(httpSolrClient);
+    }
+
+    return solrClients;
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/java/org/apache/solr/prometheus/collector/config/SolrCollectorConfig.java
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/src/java/org/apache/solr/prometheus/collector/config/SolrCollectorConfig.java b/solr/contrib/prometheus-exporter/src/java/org/apache/solr/prometheus/collector/config/SolrCollectorConfig.java
new file mode 100644
index 0000000..8344802
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/src/java/org/apache/solr/prometheus/collector/config/SolrCollectorConfig.java
@@ -0,0 +1,64 @@
+/*
+ * 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.prometheus.collector.config;
+
+import org.apache.solr.prometheus.scraper.config.SolrScraperConfig;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * SolrCollectorConfig
+ */
+public class SolrCollectorConfig {
+  private SolrScraperConfig ping = new SolrScraperConfig();
+  private SolrScraperConfig metrics = new SolrScraperConfig();
+  private SolrScraperConfig collections = new SolrScraperConfig();
+  private List<SolrScraperConfig> queries = new ArrayList<>();
+
+  public SolrScraperConfig getPing() {
+    return ping;
+  }
+
+  public void setPing(SolrScraperConfig ping) {
+    this.ping = ping;
+  }
+
+  public SolrScraperConfig getMetrics() {
+    return metrics;
+  }
+
+  public void setMetrics(SolrScraperConfig metrics) {
+    this.metrics = metrics;
+  }
+
+  public SolrScraperConfig getCollections() {
+    return collections;
+  }
+
+  public void setCollections(SolrScraperConfig collections) {
+    this.collections = collections;
+  }
+
+  public List<SolrScraperConfig> getQueries() {
+    return queries;
+  }
+
+  public void setQueries(List<SolrScraperConfig> queries) {
+    this.queries = queries;
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/java/org/apache/solr/prometheus/exporter/SolrExporter.java
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/src/java/org/apache/solr/prometheus/exporter/SolrExporter.java b/solr/contrib/prometheus-exporter/src/java/org/apache/solr/prometheus/exporter/SolrExporter.java
new file mode 100644
index 0000000..a51207d
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/src/java/org/apache/solr/prometheus/exporter/SolrExporter.java
@@ -0,0 +1,254 @@
+/*
+ * 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.prometheus.exporter;
+
+import org.apache.solr.prometheus.collector.SolrCollector;
+import org.apache.solr.prometheus.collector.config.SolrCollectorConfig;
+import io.prometheus.client.CollectorRegistry;
+import io.prometheus.client.Counter;
+import io.prometheus.client.exporter.HTTPServer;
+import net.sourceforge.argparse4j.ArgumentParsers;
+import net.sourceforge.argparse4j.impl.Arguments;
+import net.sourceforge.argparse4j.inf.ArgumentParser;
+import net.sourceforge.argparse4j.inf.ArgumentParserException;
+import net.sourceforge.argparse4j.inf.Namespace;
+import org.apache.solr.client.solrj.SolrClient;
+import org.apache.solr.client.solrj.impl.CloudSolrClient;
+import org.apache.solr.client.solrj.impl.HttpSolrClient;
+import org.apache.solr.client.solrj.impl.NoOpResponseParser;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.yaml.snakeyaml.Yaml;
+
+import javax.management.MalformedObjectNameException;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * SolrExporter
+ */
+public class SolrExporter {
+  private static final Logger logger = LoggerFactory.getLogger(SolrExporter.class);
+
+  private static final String[] ARG_PORT_FLAGS = { "-p", "--port" };
+  private static final String ARG_PORT_METAVAR = "PORT";
+  private static final String ARG_PORT_DEST = "port";
+  private static final Integer ARG_PORT_DEFAULT = 9983;
+  private static final String ARG_PORT_HELP = "solr-exporter listen port";
+
+  private static final String[] ARG_BASE_URL_FLAGS = { "-b", "--baseurl" };
+  private static final String ARG_BASE_URL_METAVAR = "BASE_URL";
+  private static final String ARG_BASE_URL_DEST = "baseUrl";
+  private static final String ARG_BASE_URL_DEFAULT = "";
+  private static final String ARG_BASE_URL_HELP = "specify Solr base URL when connecting to Solr in standalone mode (for example 'http://localhost:8983/solr')";
+
+  private static final String[] ARG_ZK_HOST_FLAGS = { "-z", "--zkhost" };
+  private static final String ARG_ZK_HOST_METAVAR = "ZK_HOST";
+  private static final String ARG_ZK_HOST_DEST = "zkHost";
+  private static final String ARG_ZK_HOST_DEFAULT = "";
+  private static final String ARG_ZK_HOST_HELP = "specify ZooKeeper connection string when connecting to Solr in SolrCloud mode (for example 'localhost:2181/solr')";
+
+  private static final String[] ARG_CONFIG_FLAGS = { "-f", "--config-file" };
+  private static final String ARG_CONFIG_METAVAR = "CONFIG";
+  private static final String ARG_CONFIG_DEST = "configFile";
+  private static final String ARG_CONFIG_DEFAULT = "./conf/config.yml";
+  private static final String ARG_CONFIG_HELP = "specify configuration file";
+
+  private static final String[] ARG_NUM_THREADS_FLAGS = { "-n", "--num-thread" };
+  private static final String ARG_NUM_THREADS_METAVAR = "NUM_THREADS";
+  private static final String ARG_NUM_THREADS_DEST = "numThreads";
+  private static final Integer ARG_NUM_THREADS_DEFAULT = 1;
+  private static final String ARG_NUM_THREADS_HELP = "specify number of threads";
+
+  private int port;
+  private SolrClient solrClient;
+  private SolrCollectorConfig config;
+  private int numThreads;
+
+  CollectorRegistry registry = new CollectorRegistry();
+
+  private HTTPServer httpServer;
+  private SolrCollector collector;
+
+  public static final Counter scrapeErrorTotal = Counter.build()
+      .name("solr_exporter_scrape_error_total")
+      .help("Number of scrape error.").register();
+
+  /**
+   * Constructor.
+   */
+  public SolrExporter(int port, SolrClient solrClient, File configFile, int numThreads) throws IOException {
+    this(port, solrClient, new Yaml().loadAs(new FileReader(configFile), SolrCollectorConfig.class), numThreads);
+  }
+
+  /**
+   * Constructor.
+   */
+  public SolrExporter(int port, SolrClient solrClient, SolrCollectorConfig config, int numThreads) {
+    super();
+
+    this.port = port;
+    this.solrClient = solrClient;
+    this.config = config;
+    this.numThreads = numThreads;
+  }
+
+  /**
+   * Start HTTP server for exporting Solr metrics.
+   */
+  public void start() throws MalformedObjectNameException, IOException {
+    InetSocketAddress socket = new InetSocketAddress(port);
+
+    this.collector = new SolrCollector(solrClient, config, numThreads);
+
+    this.registry.register(this.collector);
+    this.registry.register(scrapeErrorTotal);
+
+    this.httpServer = new HTTPServer(socket, this.registry);
+  }
+
+  /**
+   * Stop HTTP server for exporting Solr metrics.
+   */
+  public void stop() throws IOException {
+    this.httpServer.stop();
+    this.registry.unregister(this.collector);
+  }
+
+  /**
+   * Create Solr client
+   */
+  private static SolrClient createClient(String connStr) {
+    SolrClient solrClient;
+
+    Pattern baseUrlPattern = Pattern.compile("^https?:\\/\\/[\\w\\/:%#\\$&\\?\\(\\)~\\.=\\+\\-]+$");
+    Pattern zkHostPattern = Pattern.compile("^(?<host>[^\\/]+)(?<chroot>|(?:\\/.*))$");
+    Matcher matcher;
+
+    matcher = baseUrlPattern.matcher(connStr);
+    if (matcher.matches()) {
+      NoOpResponseParser responseParser = new NoOpResponseParser();
+      responseParser.setWriterType("json");
+
+      HttpSolrClient.Builder builder = new HttpSolrClient.Builder();
+      builder.withBaseSolrUrl(connStr);
+
+      HttpSolrClient httpSolrClient = builder.build();
+      httpSolrClient.setParser(responseParser);
+
+      solrClient = httpSolrClient;
+    } else {
+      String host = "";
+      String chroot = "";
+
+      matcher = zkHostPattern.matcher(connStr);
+      if (matcher.matches()) {
+        host = matcher.group("host") != null ? matcher.group("host") : "";
+        chroot = matcher.group("chroot") != null ? matcher.group("chroot") : "";
+      }
+
+      NoOpResponseParser responseParser = new NoOpResponseParser();
+      responseParser.setWriterType("json");
+
+      CloudSolrClient.Builder builder = new CloudSolrClient.Builder();
+      if (host.contains(",")) {
+        List<String> hosts = new ArrayList<>();
+        for (String h : host.split(",")) {
+          if (h != null && !h.equals("")) {
+            hosts.add(h.trim());
+          }
+        }
+        builder.withZkHost(hosts);
+      } else {
+        builder.withZkHost(host);
+      }
+      if (chroot.equals("")) {
+        builder.withZkChroot("/");
+      } else {
+        builder.withZkChroot(chroot);
+      }
+
+      CloudSolrClient cloudSolrClient = builder.build();
+      cloudSolrClient.setParser(responseParser);
+
+      solrClient = cloudSolrClient;
+    }
+
+    return solrClient;
+  }
+
+  /**
+   * Entry point of SolrExporter.
+   */
+  public static void main( String[] args ) {
+    ArgumentParser parser = ArgumentParsers.newArgumentParser(SolrCollector.class.getSimpleName())
+        .description("Prometheus exporter for Apache Solr.");
+
+    parser.addArgument(ARG_PORT_FLAGS)
+        .metavar(ARG_PORT_METAVAR).dest(ARG_PORT_DEST).type(Integer.class)
+        .setDefault(ARG_PORT_DEFAULT).help(ARG_PORT_HELP);
+
+    parser.addArgument(ARG_BASE_URL_FLAGS)
+        .metavar(ARG_BASE_URL_METAVAR).dest(ARG_BASE_URL_DEST).type(String.class)
+        .setDefault(ARG_BASE_URL_DEFAULT).help(ARG_BASE_URL_HELP);
+
+    parser.addArgument(ARG_ZK_HOST_FLAGS)
+        .metavar(ARG_ZK_HOST_METAVAR).dest(ARG_ZK_HOST_DEST).type(String.class)
+        .setDefault(ARG_ZK_HOST_DEFAULT).help(ARG_ZK_HOST_HELP);
+
+    parser.addArgument(ARG_CONFIG_FLAGS)
+        .metavar(ARG_CONFIG_METAVAR).dest(ARG_CONFIG_DEST).type(String.class)
+        .setDefault(ARG_CONFIG_DEFAULT).help(ARG_CONFIG_HELP);
+
+    parser.addArgument(ARG_NUM_THREADS_FLAGS)
+        .metavar(ARG_NUM_THREADS_METAVAR).dest(ARG_NUM_THREADS_DEST).type(Integer.class)
+        .setDefault(ARG_NUM_THREADS_DEFAULT).help(ARG_NUM_THREADS_HELP);
+
+    try {
+      Namespace res = parser.parseArgs(args);
+
+      int port = res.getInt(ARG_PORT_DEST);
+
+      String connStr = "http://localhost:8983/solr";
+      if (!res.getString(ARG_BASE_URL_DEST).equals("")) {
+        connStr = res.getString(ARG_BASE_URL_DEST);
+      } else if (!res.getString(ARG_ZK_HOST_DEST).equals("")) {
+        connStr = res.getString(ARG_ZK_HOST_DEST);
+      }
+
+      File configFile = new File(res.getString(ARG_CONFIG_DEST));
+      int numThreads = res.getInt(ARG_NUM_THREADS_DEST);
+
+      SolrClient solrClient = createClient(connStr);
+
+      SolrExporter solrExporter = new SolrExporter(port, solrClient, configFile, numThreads);
+      solrExporter.start();
+      logger.info("Start server");
+    } catch (MalformedObjectNameException | IOException e) {
+      logger.error("Start server failed: " + e.toString());
+    } catch (ArgumentParserException e) {
+      parser.handleError(e);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/java/org/apache/solr/prometheus/scraper/SolrScraper.java
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/src/java/org/apache/solr/prometheus/scraper/SolrScraper.java b/solr/contrib/prometheus-exporter/src/java/org/apache/solr/prometheus/scraper/SolrScraper.java
new file mode 100644
index 0000000..56929fc
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/src/java/org/apache/solr/prometheus/scraper/SolrScraper.java
@@ -0,0 +1,218 @@
+/*
+ * 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.prometheus.scraper;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.solr.prometheus.exporter.SolrExporter;
+import org.apache.solr.prometheus.scraper.config.SolrQueryConfig;
+import org.apache.solr.prometheus.scraper.config.SolrScraperConfig;
+import io.prometheus.client.Collector;
+import net.thisptr.jackson.jq.JsonQuery;
+import net.thisptr.jackson.jq.exception.JsonQueryException;
+import org.apache.solr.client.solrj.SolrClient;
+import org.apache.solr.client.solrj.SolrServerException;
+import org.apache.solr.client.solrj.impl.CloudSolrClient;
+import org.apache.solr.client.solrj.impl.HttpSolrClient;
+import org.apache.solr.client.solrj.request.QueryRequest;
+import org.apache.solr.common.params.ModifiableSolrParams;
+import org.apache.solr.common.util.NamedList;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Callable;
+
+/**
+ * SolrScraper
+ */
+public class SolrScraper implements Callable<Map<String, Collector.MetricFamilySamples>> {
+  private static final Logger logger = LoggerFactory.getLogger(SolrScraper.class);
+
+  private SolrClient solrClient;
+  private SolrScraperConfig scraperConfig;
+
+  private List<String> labelNames;
+  private List<String> labelValues;
+
+  /**
+   * Constructor.
+   */
+  public SolrScraper(SolrClient solrClient, SolrScraperConfig scraperConfig) {
+    this(solrClient, scraperConfig, new ArrayList<>(), new ArrayList<>());
+  }
+
+  /**
+   * Constructor.
+   */
+  public SolrScraper(SolrClient solrClient, SolrScraperConfig scraperConfig, List<String> labelNames, List<String> labelValues) {
+    super();
+
+    this.solrClient = solrClient;
+    this.scraperConfig = scraperConfig;
+
+    this.labelNames = labelNames;
+    this.labelValues = labelValues;
+  }
+
+  /**
+   * Execute collectResponse
+   */
+  @Override
+  public Map<String, Collector.MetricFamilySamples> call() throws Exception {
+    return collectResponse(this.solrClient, this.scraperConfig);
+  }
+
+  /**
+   * Collect facet count.
+   */
+  public Map<String, Collector.MetricFamilySamples> collectResponse(SolrClient solrClient, SolrScraperConfig scraperConfig) {
+    Map<String, Collector.MetricFamilySamples> metricFamilySamplesMap = new LinkedHashMap<>();
+
+    try {
+      SolrQueryConfig queryConfig = scraperConfig.getQuery();
+
+      // create Solr request parameters
+      ModifiableSolrParams params = new ModifiableSolrParams();
+      for (Map<String, String> param : queryConfig.getParams()) {
+        for (String name : param.keySet()) {
+          Object obj = param.get(name);
+          if (obj instanceof Number) {
+            params.add(name, obj.toString());
+          } else {
+            params.add(name, param.get(name));
+          }
+        }
+      }
+
+      // create Solr queryConfig request
+      QueryRequest queryRequest = new QueryRequest(params);
+      queryRequest.setPath(queryConfig.getPath());
+
+      // invoke Solr
+      NamedList<Object> queryResponse = null;
+      if (queryConfig.getCore().equals("") && queryConfig.getCollection().equals("")) {
+        queryResponse = solrClient.request(queryRequest);
+      } else if (!queryConfig.getCore().equals("")) {
+        queryResponse = solrClient.request(queryRequest, queryConfig.getCore());
+      } else if (!queryConfig.getCollection().equals("")) {
+        queryResponse = solrClient.request(queryRequest, queryConfig.getCollection());
+      }
+
+      ObjectMapper om = new ObjectMapper();
+
+      JsonNode metricsJson = om.readTree((String) queryResponse.get("response"));
+
+      List<JsonQuery> jqs = new ArrayList<>();
+      for (String jsonQuery : scraperConfig.getJsonQueries()) {
+        JsonQuery compiledJsonQuery = JsonQuery.compile(jsonQuery);
+        jqs.add(compiledJsonQuery);
+      }
+
+      for (int i = 0; i < jqs.size(); i++) {
+        JsonQuery q = jqs.get(i);
+        try {
+          List<JsonNode> results = q.apply(metricsJson);
+          for (JsonNode result : results) {
+            String type = result.get("type").textValue();
+            String name = result.get("name").textValue();
+            String help = result.get("help").textValue();
+            Double value = result.get("value").doubleValue();
+            ArrayList<String> labelNames = new ArrayList<>(this.labelNames);
+            ArrayList<String> labelValues = new ArrayList<>(this.labelValues);
+
+            if (solrClient instanceof CloudSolrClient) {
+              labelNames.add("zk_host");
+              labelValues.add(((CloudSolrClient) solrClient).getZkHost());
+            }
+
+            if (!scraperConfig.getQuery().getCollection().equals("")) {
+              labelNames.add("collection");
+              labelValues.add(scraperConfig.getQuery().getCollection());
+            }
+
+            if (solrClient instanceof HttpSolrClient) {
+              labelNames.add("base_url");
+              labelValues.add(((HttpSolrClient) solrClient).getBaseURL());
+            }
+
+            if (!scraperConfig.getQuery().getCore().equals("")) {
+              labelNames.add("core");
+              labelValues.add(scraperConfig.getQuery().getCore());
+            }
+
+            for(Iterator<JsonNode> ite = result.get("label_names").iterator();ite.hasNext();){
+              JsonNode item = ite.next();
+              labelNames.add(item.textValue());
+            }
+            for(Iterator<JsonNode> ite = result.get("label_values").iterator();ite.hasNext();){
+              JsonNode item = ite.next();
+              labelValues.add(item.textValue());
+            }
+
+            if (labelNames.indexOf("core") < 0 && labelNames.indexOf("collection") >= 0 && labelNames.indexOf("shard") >= 0 && labelNames.indexOf("replica") >= 0) {
+              if (labelValues.get(labelNames.indexOf("collection")).equals("-") && labelValues.get(labelNames.indexOf("shard")).equals("-") && labelValues.get(labelNames.indexOf("replica")).equals("-")) {
+                labelNames.add("core");
+                labelValues.add("-");
+              } else {
+                StringBuffer sb = new StringBuffer();
+                sb.append(labelValues.get(labelNames.indexOf("collection")))
+                    .append("_")
+                    .append(labelValues.get(labelNames.indexOf("shard")))
+                    .append("_")
+                    .append(labelValues.get(labelNames.indexOf("replica")));
+
+                labelNames.add("core");
+                labelValues.add(sb.toString());
+              }
+            }
+
+            if (!metricFamilySamplesMap.containsKey(name)) {
+              Collector.MetricFamilySamples metricFamilySamples = new Collector.MetricFamilySamples(
+                name,
+                Collector.Type.valueOf(type),
+                help,
+                new ArrayList<>()
+              );
+              metricFamilySamplesMap.put(name, metricFamilySamples);
+            }
+
+            Collector.MetricFamilySamples.Sample sample = new Collector.MetricFamilySamples.Sample(name, labelNames, labelValues, value);
+
+            if (!metricFamilySamplesMap.get(name).samples.contains(sample)) {
+              metricFamilySamplesMap.get(name).samples.add(sample);
+            }
+          }
+        } catch (JsonQueryException e) {
+          logger.error(e.toString() + " " + q.toString());
+          SolrExporter.scrapeErrorTotal.inc();
+        }
+      }
+    } catch (HttpSolrClient.RemoteSolrException | SolrServerException | IOException e) {
+      logger.error(e.toString());
+    } catch (Exception e) {
+      logger.error(e.toString());
+    }
+
+    return metricFamilySamplesMap;
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/java/org/apache/solr/prometheus/scraper/config/SolrQueryConfig.java
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/src/java/org/apache/solr/prometheus/scraper/config/SolrQueryConfig.java b/solr/contrib/prometheus-exporter/src/java/org/apache/solr/prometheus/scraper/config/SolrQueryConfig.java
new file mode 100644
index 0000000..500bb03
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/src/java/org/apache/solr/prometheus/scraper/config/SolrQueryConfig.java
@@ -0,0 +1,99 @@
+/*
+ * 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.prometheus.scraper.config;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+
+/**
+ * SolrQueryConfig
+ */
+public class SolrQueryConfig implements Cloneable {
+  private String core = "";
+  private String collection = "";
+  private String path = "";
+  private List<LinkedHashMap<String, String>> params = new ArrayList<>();
+
+  public String getCore() {
+    return core;
+  }
+
+  public void setCore(String core) {
+    this.core = core;
+  }
+
+  public String getCollection() {
+    return collection;
+  }
+
+  public void setCollection(String collection) {
+    this.collection = collection;
+  }
+
+  public String getPath() {
+    return path;
+  }
+
+  public void setPath(String path) {
+    this.path = path;
+  }
+
+  public List<LinkedHashMap<String, String>> getParams() {
+    return params;
+  }
+
+  public void setParams(List<LinkedHashMap<String, String>> params) {
+    this.params = params;
+  }
+
+  public String getParamsString() {
+    StringBuffer buffer = new StringBuffer();
+
+    for(Iterator<LinkedHashMap<String, String>> i = getParams().iterator(); i.hasNext(); ) {
+      LinkedHashMap<String, String> param = i.next();
+      for(Iterator<String> j = param.keySet().iterator(); j.hasNext(); ) {
+        String name = j.next();
+        buffer.append(name).append("=").append(param.get(name));
+        if (j.hasNext()) {
+          buffer.append("&");
+        }
+      }
+      if (i.hasNext()) {
+        buffer.append("&");
+      }
+    }
+
+    return buffer.toString();
+  }
+
+  public SolrQueryConfig clone() throws CloneNotSupportedException {
+    SolrQueryConfig queryConfig = null;
+
+    try {
+      queryConfig = (SolrQueryConfig) super.clone();
+      queryConfig.setCore(new String(this.core));
+      queryConfig.setCollection(new String(this.collection));
+      queryConfig.setParams(new ArrayList<>(this.params));
+    }catch (Exception e){
+      e.printStackTrace();
+    }
+
+    return queryConfig;
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/java/org/apache/solr/prometheus/scraper/config/SolrScraperConfig.java
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/src/java/org/apache/solr/prometheus/scraper/config/SolrScraperConfig.java b/solr/contrib/prometheus-exporter/src/java/org/apache/solr/prometheus/scraper/config/SolrScraperConfig.java
new file mode 100644
index 0000000..3e3a36f
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/src/java/org/apache/solr/prometheus/scraper/config/SolrScraperConfig.java
@@ -0,0 +1,60 @@
+/*
+ * 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.prometheus.scraper.config;
+
+import net.thisptr.jackson.jq.exception.JsonQueryException;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * SolrScraperConfig
+ */
+public class SolrScraperConfig implements Cloneable {
+  private SolrQueryConfig query = new SolrQueryConfig();
+  private List<String> jsonQueries = new ArrayList<>();
+
+  public SolrQueryConfig getQuery() {
+    return this.query;
+  }
+
+  public void setQuery(SolrQueryConfig query) {
+    this.query = query;
+  }
+
+  public List<String> getJsonQueries() {
+    return jsonQueries;
+  }
+
+  public void setJsonQueries(List<String> jsonQueries) throws JsonQueryException {
+    this.jsonQueries = jsonQueries;
+  }
+
+  public SolrScraperConfig clone() throws CloneNotSupportedException {
+    SolrScraperConfig scraperConfig = null;
+
+    try {
+      scraperConfig = (SolrScraperConfig) super.clone();
+      scraperConfig.setQuery(this.query.clone());
+      scraperConfig.setJsonQueries(new ArrayList<>(this.jsonQueries));
+    }catch (Exception e){
+      e.printStackTrace();
+    }
+
+    return scraperConfig;
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/java/overview.html
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/src/java/overview.html b/solr/contrib/prometheus-exporter/src/java/overview.html
new file mode 100644
index 0000000..6c7dfce
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/src/java/overview.html
@@ -0,0 +1,21 @@
+<!--
+ 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.
+-->
+<html>
+<body>
+Apache Solr Search Server: Solr Prometheus Exporter contrib
+</body>
+</html>


[3/7] lucene-solr:master: SOLR-11795: Add Solr metrics exporter for Prometheus

Posted by ko...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4bfcbc5c/solr/contrib/prometheus-exporter/src/test-files/conf/config.yml
----------------------------------------------------------------------
diff --git a/solr/contrib/prometheus-exporter/src/test-files/conf/config.yml b/solr/contrib/prometheus-exporter/src/test-files/conf/config.yml
new file mode 100644
index 0000000..e441f10
--- /dev/null
+++ b/solr/contrib/prometheus-exporter/src/test-files/conf/config.yml
@@ -0,0 +1,1840 @@
+#
+# 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.
+#
+
+ping:
+  query:
+    path: /admin/ping
+  jsonQueries:
+    - |-
+      . as $object | $object |
+      (if $object.status == "OK" then 1.0 else 0.0 end) as $value |
+      {
+        name         : "solr_ping",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/ping.html",
+        label_names  : [],
+        label_values : [],
+        value        : $value
+      }
+
+metrics:
+  query:
+    path: /admin/metrics
+    params:
+      - group: 'all'
+      - type: 'all'
+      - prefix: ''
+      - property: ''
+  jsonQueries:
+#    ##############################
+#    # jetty
+#    ##############################
+#    # solr_metrics_jetty_response_total
+#    - |-
+#      .metrics["solr.jetty"] | to_entries | .[] | select(.key | startswith("org.eclipse.jetty.server.handler.DefaultHandler")) | select(.key | endswith("xx-responses")) as $object |
+#      $object.key | split(".") | last | split("-") | first as $status |
+#      $object.value.count as $value |
+#      {
+#        name         : "solr_metrics_jetty_response_total",
+#        type         : "COUNTER",
+#        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+#        label_names  : ["status"],
+#        label_values : [$status],
+#        value        : $value
+#      }
+#
+#    # solr_metrics_jetty_requests_total
+#    - |-
+#      .metrics["solr.jetty"] | to_entries | .[] | select(.key | startswith("org.eclipse.jetty.server.handler.DefaultHandler.")) | select(.key | endswith("-requests")) | select (.value | type == "object") as $object |
+#      $object.key | split(".") | last | split("-") | first as $method |
+#      $object.value.count as $value |
+#      {
+#        name         : "solr_metrics_jetty_requests_total",
+#        type         : "COUNTER",
+#        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+#        label_names  : ["method"],
+#        label_values : [$method],
+#        value        : $value
+#      }
+#
+#    # solr_metrics_jetty_dispatches_total
+#    - |-
+#      .metrics["solr.jetty"] | to_entries | .[] | select(.key == "org.eclipse.jetty.server.handler.DefaultHandler.dispatches") as $object |
+#      $object.value.count as $value |
+#      {
+#        name         : "solr_metrics_jetty_dispatches_total",
+#        type         : "COUNTER",
+#        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+#        label_names  : [],
+#        label_values : [],
+#        value        : $value
+#      }
+
+    ##############################
+    # jvm
+    ##############################
+    # solr_metrics_jvm_buffers
+    - |-
+      .metrics["solr.jvm"] | to_entries | .[] | select(.key | startswith("buffers.")) | select(.key | endswith(".Count")) as $object |
+      $object.key | split(".")[1] as $pool |
+      $object.value as $value |
+      {
+        name         : "solr_metrics_jvm_buffers",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["pool"],
+        label_values : [$pool],
+        value        : $value
+      }
+
+    # solr_metrics_jvm_buffers_bytes
+    - |-
+      .metrics["solr.jvm"] | to_entries | .[] | select(.key | startswith("buffers.")) | select(.key | (endswith(".MemoryUsed") or endswith(".TotalCapacity"))) as $object |
+      $object.key | split(".")[1] as $pool |
+      $object.key | split(".") | last as $item |
+      $object.value as $value |
+      {
+        name         : "solr_metrics_jvm_buffers_bytes",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["pool", "item"],
+        label_values : [$pool, $item],
+        value        : $value
+      }
+
+    # solr_metrics_jvm_gc_total
+    - |-
+      .metrics["solr.jvm"] | to_entries | .[] | select(.key | startswith("gc.")) | select(.key | endswith(".count")) as $object |
+      $object.key | split(".")[1] as $item |
+      $object.value as $value |
+      {
+        name         : "solr_metrics_jvm_gc_total",
+        type         : "COUNTER",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["item"],
+        label_values : [$item],
+        value        : $value
+      }
+
+    # solr_metrics_jvm_gc_seconds_total
+    - |-
+      .metrics["solr.jvm"] | to_entries | .[] | select(.key | startswith("gc.")) | select(.key | endswith(".time")) as $object |
+      $object.key | split(".")[1] as $item |
+      ($object.value / 1000) as $value |
+      {
+        name         : "solr_metrics_jvm_gc_seconds_total",
+        type         : "COUNTER",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["item"],
+        label_values : [$item],
+        value        : $value
+      }
+
+    # solr_metrics_jvm_memory_heap_bytes
+    - |-
+      .metrics["solr.jvm"] | to_entries | .[] | select(.key | startswith("memory.heap.")) | select(.key | endswith(".usage") | not) as $object |
+      $object.key | split(".") | last as $item |
+      $object.value as $value |
+      {
+        name         : "solr_metrics_jvm_memory_heap_bytes",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["item"],
+        label_values : [$item],
+        value        : $value
+      }
+
+    # solr_metrics_jvm_memory_non_heap_bytes
+    - |-
+      .metrics["solr.jvm"] | to_entries | .[] | select(.key | startswith("memory.non-heap.")) | select(.key | endswith(".usage") | not) as $object |
+      $object.key | split(".") | last as $item |
+      $object.value as $value |
+      {
+        name         : "solr_metrics_jvm_memory_non_heap_bytes",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["item"],
+        label_values : [$item],
+        value        : $value
+      }
+
+    # solr_metrics_jvm_memory_pools_bytes
+    - |-
+      .metrics["solr.jvm"] | to_entries | .[] | select(.key | startswith("memory.pools.")) | select(.key | endswith(".usage") | not) as $object |
+      $object.key | split(".")[2] as $space |
+      $object.key | split(".") | last as $item |
+      $object.value as $value |
+      {
+        name         : "solr_metrics_jvm_memory_pools_bytes",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["space", "item"],
+        label_values : [$space, $item],
+        value        : $value
+      }
+
+    # solr_metrics_jvm_memory_bytes
+    - |-
+      .metrics["solr.jvm"] | to_entries | .[] | select(.key | startswith("memory.total.")) as $object |
+      $object.key | split(".") | last as $item |
+      $object.value as $value |
+      {
+        name         : "solr_metrics_jvm_memory_bytes",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["item"],
+        label_values : [$item],
+        value        : $value
+      }
+
+    # solr_metrics_jvm_os_memory_bytes
+    - |-
+      .metrics["solr.jvm"] | to_entries | .[] | select(.key == "os.committedVirtualMemorySize" or .key == "os.freePhysicalMemorySize" or .key == "os.freeSwapSpaceSize" or .key =="os.totalPhysicalMemorySize" or .key == "os.totalSwapSpaceSize") as $object |
+      $object.key | split(".") | last as $item |
+      $object.value as $value |
+      {
+        name         : "solr_metrics_jvm_os_memory_bytes",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["item"],
+        label_values : [$item],
+        value        : $value
+      }
+
+    # solr_metrics_jvm_os_file_descriptors
+    - |-
+      .metrics["solr.jvm"] | to_entries | .[] | select(.key == "os.maxFileDescriptorCount" or .key == "os.openFileDescriptorCount") as $object |
+      $object.key | split(".") | last as $item |
+      $object.value as $value |
+      {
+        name         : "solr_metrics_jvm_os_file_descriptors",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["item"],
+        label_values : [$item],
+        value        : $value
+      }
+
+    # solr_metrics_jvm_os_cpu_load
+    - |-
+      .metrics["solr.jvm"] | to_entries | .[] | select(.key == "os.processCpuLoad" or .key == "os.systemCpuLoad") as $object |
+      $object.key | split(".") | last as $item |
+      $object.value as $value |
+      {
+        name         : "solr_metrics_jvm_os_cpu_load",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["item"],
+        label_values : [$item],
+        value        : $value
+      }
+
+    # solr_metrics_jvm_os_cpu_time_seconds
+    - |-
+      .metrics["solr.jvm"] | to_entries | .[] | select(.key == "os.processCpuTime") as $object |
+      ($object.value / 1000.0) as $value |
+      {
+        name         : "solr_metrics_jvm_os_cpu_time_seconds",
+        type         : "COUNTER",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["item"],
+        label_values : ["processCpuTime"],
+        value        : $value
+      }
+
+    # solr_metrics_jvm_os_load_average
+    - |-
+      .metrics["solr.jvm"] | to_entries | .[] | select(.key == "os.systemLoadAverage") as $object |
+      $object.value as $value |
+      {
+        name         : "solr_metrics_jvm_os_load_average",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["item"],
+        label_values : ["systemLoadAverage"],
+        value        : $value
+      }
+
+    # solr_metrics_jvm_threads
+    - |-
+      .metrics["solr.jvm"] | to_entries | .[] | select(.key | startswith("threads.")) | select(.key | endswith(".count")) as $object |
+      $object.key | split(".")[1] as $item |
+      $object.value as $value |
+      {
+        name         : "solr_metrics_jvm_threads",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["item"],
+        label_values : [$item],
+        value        : $value
+      }
+
+    # solr_metrics_node_client_errors_total
+    - |-
+      .metrics["solr.node"] | to_entries | .[] | select(.key | endswith(".clientErrors")) as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value.count as $value |
+      {
+        name         : "solr_metrics_node_client_errors_total",
+        type         : "COUNTER",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["category", "handler"],
+        label_values : [$category, $handler],
+        value        : $value
+      }
+
+    # solr_metrics_node_errors_total
+    - |-
+      .metrics["solr.node"] | to_entries | .[] | select(.key | endswith(".clientErrors")) as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value.count as $value |
+      {
+        name         : "solr_metrics_node_errors_total",
+        type         : "COUNTER",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["category", "handler"],
+        label_values : [$category, $handler],
+        value        : $value
+      }
+
+    # solr_metrics_node_requests_total
+    - |-
+      .metrics["solr.node"] | to_entries | .[] | select(.key | endswith(".requestTimes")) as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value.count as $value |
+      {
+        name         : "solr_metrics_node_requests_total",
+        type         : "COUNTER",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["category", "handler"],
+        label_values : [$category, $handler],
+        value        : $value
+      }
+
+    # solr_metrics_node_server_errors_total
+    - |-
+      .metrics["solr.node"] | to_entries | .[] | select(.key | endswith(".serverErrors")) as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value.count as $value |
+      {
+        name         : "solr_metrics_node_server_errors_total",
+        type         : "COUNTER",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["category", "handler"],
+        label_values : [$category, $handler],
+        value        : $value
+      }
+
+    # solr_metrics_node_timeouts_total
+    - |-
+      .metrics["solr.node"] | to_entries | .[] | select(.key | endswith(".timeouts")) as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value.count as $value |
+      {
+        name         : "solr_metrics_node_timeouts_total",
+        type         : "COUNTER",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["category", "handler"],
+        label_values : [$category, $handler],
+        value        : $value
+      }
+
+    # solr_metrics_node_time_seconds_total
+    - |-
+      .metrics["solr.node"] | to_entries | .[] | select(.key | endswith(".totalTime")) as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      ($object.value / 1000) as $value |
+      {
+        name         : "solr_metrics_node_time_seconds_total",
+        type         : "COUNTER",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["category", "handler"],
+        label_values : [$category, $handler],
+        value        : $value
+      }
+
+    # solr_metrics_node_cores
+    - |-
+      .metrics["solr.node"] | to_entries | .[] | select(.key | startswith("CONTAINER.cores.")) as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[2] as $item |
+      $object.value as $value |
+      {
+        name         : "solr_metrics_node_cores",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["category", "item"],
+        label_values : [$category, $item],
+        value        : $value
+      }
+
+    # solr_metrics_node_core_root_fs_bytes
+    - |-
+      .metrics["solr.node"] | to_entries | .[] | select(.key | startswith("CONTAINER.fs.coreRoot.")) | select(.key | endswith(".totalSpace") or endswith(".usableSpace")) as $object |
+      $object.key | split(".") as $key_items |
+      $key_items | length as $label_len |
+      $key_items[0] as $category |
+      $key_items[3] as $item |
+      $object.value as $value |
+      {
+        name         : "solr_metrics_node_core_root_fs_bytes",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["category", "item"],
+        label_values : [$category, $item],
+        value        : $value
+      }
+
+    # solr_metrics_node_thread_pool_completed_total
+    - |-
+      .metrics["solr.node"] | to_entries | .[] | select(.key | contains(".threadPool.")) | select(.key | endswith(".completed")) as $object |
+      $object.key | split(".") as $key_items |
+      $key_items | length as $label_len |
+      $key_items[0] as $category |
+      (if $label_len >= 5 then $key_items[1] else "" end) as $handler |
+      (if $label_len >= 5 then $key_items[3] else $key_items[2] end) as $executor |
+      $object.value.count as $value |
+      {
+        name         : "solr_metrics_node_thread_pool_completed_total",
+        type         : "COUNTER",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["category", "handler", "executor"],
+        label_values : [$category, $handler, $executor],
+        value        : $value
+      }
+
+    # solr_metrics_node_thread_pool_running
+    - |-
+      .metrics["solr.node"] | to_entries | .[] | select(.key | contains(".threadPool.")) | select(.key | endswith(".running")) as $object |
+      $object.key | split(".") as $key_items |
+      $key_items | length as $label_len |
+      $key_items[0] as $category |
+      (if $label_len >= 5 then $key_items[1] else "" end) as $handler |
+      (if $label_len >= 5 then $key_items[3] else $key_items[2] end) as $executor |
+      $object.value as $value |
+      {
+        name         : "solr_metrics_node_thread_pool_running",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["category", "handler", "executor"],
+        label_values : [$category, $handler, $executor],
+        value        : $value
+      }
+
+    # solr_metrics_node_thread_pool_submitted_total
+    - |-
+      .metrics["solr.node"] | to_entries | .[] | select(.key | contains(".threadPool.")) | select(.key | endswith(".submitted")) as $object |
+      $object.key | split(".") as $key_items |
+      $key_items | length as $label_len |
+      $key_items[0] as $category |
+      (if $label_len >= 5 then $key_items[1] else "" end) as $handler |
+      (if $label_len >= 5 then $key_items[3] else $key_items[2] end) as $executor |
+      $object.value.count as $value |
+      {
+        name         : "solr_metrics_node_thread_pool_submitted_total",
+        type         : "COUNTER",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["category", "handler", "executor"],
+        label_values : [$category, $handler, $executor],
+        value        : $value
+      }
+
+    # solr_metrics_node_connections
+    - |-
+      .metrics["solr.node"] | to_entries | .[] | select(.key | endswith("Connections")) as $object |
+      $object.key | split(".") as $key_items |
+      $key_items | length as $label_len |
+      $key_items[0] as $category |
+      $key_items[1] as $handler |
+      $key_items[2] as $item |
+      $object.value as $value |
+      {
+        name         : "solr_metrics_node_connections",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names  : ["category", "handler", "item"],
+        label_values : [$category, $handler, $item],
+        value        : $value
+      }
+
+    ##############################
+    # core
+    ##############################
+    # solr_metrics_core_client_errors_total
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key | endswith(".clientErrors")) as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      select($handler | startswith("/")) |
+      $object.value.count as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_client_errors_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_client_errors_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_errors_total
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key | endswith(".errors")) | select (.value | type == "object") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      select($handler | startswith("/")) |
+      $object.value.count as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_errors_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_errors_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_requests_total
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key | endswith(".requestTimes")) | select (.value | type == "object") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      select($handler | startswith("/")) |
+      $object.value.count as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_requests_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_requests_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_server_errors_total
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key | endswith(".serverErrors")) | select (.value | type == "object") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      select($handler | startswith("/")) |
+      $object.value.count as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_server_errors_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_server_errors_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_timeouts_total
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key | endswith(".timeouts")) | select (.value | type == "object") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      select($handler | startswith("/")) |
+      $object.value.count as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_timeouts_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_timeouts_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_time_seconds_total
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key | endswith(".totalTime")) as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      select($handler | startswith("/")) |
+      ($object.value / 1000) as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_time_seconds_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_time_seconds_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_field_cache_total
+    - |-
+      .metrics | to_entries | .[] | select (.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "CACHE.core.fieldCache") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.value.entries_count as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_field_cache_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "core"],
+        label_values: [$category, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_field_cache_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "core", "collection", "shard", "replica"],
+        label_values: [$category, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_searcher_cache
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key | startswith("CACHE.searcher.")) | select (.key | endswith("documentCache") or endswith("fieldValueCache") or endswith("filterCache") or endswith("perSegFilter") or endswith("queryResultCache")) as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[2] as $type |
+      $object.value | to_entries | .[] | select(.key == "lookups" or .key == "hits" or .key == "size" or .key == "evictions" or .key == "inserts") as $target |
+      $target.key as $item |
+      $target.value as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_searcher_cache",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "core", "type", "item"],
+        label_values: [$category, $core, $type, $item],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_searcher_cache",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "core", "collection", "shard", "replica", "type", "item"],
+        label_values: [$category, $core, $collection, $shard, $replica, $type, $item],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_searcher_cache_ratio
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key | startswith("CACHE.searcher.")) | select (.key | endswith("documentCache") or endswith("fieldValueCache") or endswith("filterCache") or endswith("perSegFilter") or endswith("queryResultCache")) as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[2] as $type |
+      $object.value | to_entries | .[] | select(.key == "hitratio") as $target |
+      $target.key as $item |
+      $target.value as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_searcher_cache_ratio",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "core", "type", "item"],
+        label_values: [$category, $core, $type, $item],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_searcher_cache_ratio",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "core", "collection", "shard", "replica", "type", "item"],
+        label_values: [$category, $core, $collection, $shard, $replica, $type, $item],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_searcher_warmup_time_seconds
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key | startswith("CACHE.searcher.")) | select (.key | endswith("documentCache") or endswith("fieldValueCache") or endswith("filterCache") or endswith("perSegFilter") or endswith("queryResultCache")) as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[2] as $type |
+      $object.value | to_entries | .[] | select(.key == "warmupTime") as $target |
+      $target.key as $item |
+      ($target.value / 1000) as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_searcher_warmup_time_seconds",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "core", "type", "item"],
+        label_values: [$category, $core, $type, $item],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_searcher_warmup_time_seconds",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "core", "collection", "shard", "replica", "type", "item"],
+        label_values: [$category, $core, $collection, $shard, $replica, $type, $item],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_searcher_cumulative_cache_total
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key | startswith("CACHE.searcher.")) | select (.key | endswith("documentCache") or endswith("fieldValueCache") or endswith("filterCache") or endswith("perSegFilter") or endswith("queryResultCache")) as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[2] as $type |
+      $object.value | to_entries | .[] | select(.key == "cumulative_lookups" or .key == "cumulative_hits" or .key == "cumulative_evictions" or .key == "cumulative_inserts") as $target |
+      $target.key as $item |
+      $target.value as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_searcher_cumulative_cache_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "core", "type", "item"],
+        label_values: [$category, $core, $type, $item],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_searcher_cumulative_cache_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "core", "collection", "shard", "replica", "type", "item"],
+        label_values: [$category, $core, $collection, $shard, $replica, $type, $item],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_searcher_cumulative_cache_ratio
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key | startswith("CACHE.searcher.")) | select (.key | endswith("documentCache") or endswith("fieldValueCache") or endswith("filterCache") or endswith("perSegFilter") or endswith("queryResultCache")) as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[2] as $type |
+      $object.value | to_entries | .[] | select(.key == "cumulative_hitratio") as $target |
+      $target.key as $item |
+      $target.value as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_searcher_cumulative_cache_ratio",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "core", "type", "item"],
+        label_values: [$category, $core, $type, $item],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_searcher_cumulative_cache_ratio",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "core", "collection", "shard", "replica", "type", "item"],
+        label_values: [$category, $core, $collection, $shard, $replica, $type, $item],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_fs_bytes
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key | startswith("CORE.fs.")) | select (.key | endswith(".totalSpace") or endswith(".usableSpace")) as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[2] as $item |
+      $object.value as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_fs_bytes",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "core", "item"],
+        label_values: [$category, $core, $item],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_fs_bytes",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "core", "collection", "shard", "replica", "item"],
+        label_values: [$category, $core, $collection, $shard, $replica, $item],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_highlighter_request_total
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key | startswith("HIGHLIGHTER.")) | select (.key | endswith(".requests")) as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $name |
+      $object.key | split(".")[2] as $item |
+      $object.value as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_highlighter_request_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "core", "name", "item"],
+        label_values: [$category, $core, $name, $item],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_highlighter_request_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "core", "collection", "shard", "replica", "name", "item"],
+        label_values: [$category, $core, $collection, $shard, $replica, $name, $item],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_index_size_bytes
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "INDEX.sizeInBytes") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.value as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_index_size_bytes",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "core"],
+        label_values: [$category, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_index_size_bytes",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "core", "collection", "shard", "replica"],
+        label_values: [$category, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_replication_master
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "REPLICATION./replication.isMaster") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      (if $object.value == true then 1.0 else 0.0 end) as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_replication_master",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_replication_master",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_replication_slave
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "REPLICATION./replication.isSlave") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      (if $object.value == true then 1.0 else 0.0 end) as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_replication_slave",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_replication_slave",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_searcher_documents
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "SEARCHER.searcher.deletedDocs" or .key == "SEARCHER.searcher.maxDoc" or .key == "SEARCHER.searcher.numDocs") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[2] as $item |
+      $object.value as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_searcher_documents",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "core", "item"],
+        label_values: [$category, $core, $item],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_searcher_documents",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "core", "collection", "shard", "replica", "item"],
+        label_values: [$category, $core, $collection, $shard, $replica, $item],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_update_handler_adds
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "UPDATE.updateHandler.adds") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_update_handler_adds",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_update_handler_adds",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_update_handler_auto_commits_total
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "UPDATE.updateHandler.autoCommits") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_update_handler_auto_commits_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_update_handler_auto_commits_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_update_handler_commits_total
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "UPDATE.updateHandler.commits") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value.count as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_update_handler_commits_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_update_handler_commits_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_update_handler_adds_total
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "UPDATE.updateHandler.cumulativeAdds") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value.count as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_update_handler_adds_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_update_handler_adds_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_update_handler_deletes_by_id_total
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "UPDATE.updateHandler.cumulativeDeletesById") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value.count as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_update_handler_deletes_by_id_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_update_handler_deletes_by_id_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_update_handler_deletes_by_query_total
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "UPDATE.updateHandler.cumulativeDeletesByQuery") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value.count as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_update_handler_deletes_by_query_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_update_handler_deletes_by_query_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_update_handler_errors_total
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "UPDATE.updateHandler.cumulativeErrors") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value.count as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_update_handler_errors_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_update_handler_errors_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_update_handler_deletes_by_id
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "UPDATE.updateHandler.deletesById") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_update_handler_deletes_by_id",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_update_handler_deletes_by_id",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_update_handler_deletes_by_query
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "UPDATE.updateHandler.deletesByQuery") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_update_handler_deletes_by_query",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_update_handler_deletes_by_query",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_update_handler_pending_docs
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "UPDATE.updateHandler.docsPending") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_update_handler_pending_docs",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_update_handler_pending_docs",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_update_handler_errors
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "UPDATE.updateHandler.errors") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_update_handler_errors",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_update_handler_errors",
+        type: "GAUGE",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_update_handler_expunge_deletes_total
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "UPDATE.updateHandler.expungeDeletes") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value.count as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_update_handler_expunge_deletes_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_update_handler_expunge_deletes_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_update_handler_merges_total
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "UPDATE.updateHandler.merges") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value.count as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_update_handler_merges_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_update_handler_merges_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_update_handler_optimizes_total
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "UPDATE.updateHandler.optimizes") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value.count as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_update_handler_optimizes_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_update_handler_optimizes_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_update_handler_rollbacks_total
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "UPDATE.updateHandler.rollbacks") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value.count as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_update_handler_rollbacks_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_update_handler_rollbacks_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_update_handler_soft_auto_commits_total
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "UPDATE.updateHandler.softAutoCommits") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_update_handler_soft_auto_commits_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_update_handler_soft_auto_commits_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+    # solr_metrics_core_update_handler_splits_total
+    - |-
+      .metrics | to_entries | .[] | select(.key | startswith("solr.core.")) as $parent |
+      $parent.key | split(".") as $parent_key_items |
+      $parent_key_items | length as $parent_key_item_len |
+      (if $parent_key_item_len == 3 then $parent_key_items[2] else "" end) as $core |
+      (if $parent_key_item_len == 5 then $parent_key_items[2] else "" end) as $collection |
+      (if $parent_key_item_len == 5 then $parent_key_items[3] else "" end) as $shard |
+      (if $parent_key_item_len == 5 then $parent_key_items[4] else "" end) as $replica |
+      (if $parent_key_item_len == 5 then ($collection + "_" + $shard + "_" + $replica) else $core end) as $core |
+      $parent.value | to_entries | .[] | select(.key == "UPDATE.updateHandler.splits") as $object |
+      $object.key | split(".")[0] as $category |
+      $object.key | split(".")[1] as $handler |
+      $object.value.count as $value |
+      if $parent_key_item_len == 3 then
+      {
+        name: "solr_metrics_core_update_handler_splits_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core"],
+        label_values: [$category, $handler, $core],
+        value: $value
+      }
+      else
+      {
+        name: "solr_metrics_core_update_handler_splits_total",
+        type: "COUNTER",
+        help: "See following URL: https://lucene.apache.org/solr/guide/metrics-reporting.html",
+        label_names: ["category", "handler", "core", "collection", "shard", "replica"],
+        label_values: [$category, $handler, $core, $collection, $shard, $replica],
+        value: $value
+      }
+      end
+
+
+collections:
+  query:
+    path: /admin/collections
+    params:
+      - action: 'CLUSTERSTATUS'
+  jsonQueries:
+    # solr_collections_live_nodes
+    - |-
+      .cluster.live_nodes | length as $value|
+      {
+        name         : "solr_collections_live_nodes",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/collections-api.html#clusterstatus",
+        label_names  : [],
+        label_values : [],
+        value        : $value
+      }
+
+    # solr_collections_pull_replicas
+    - |-
+      .cluster.collections | to_entries | .[] | . as $object |
+      $object.key as $collection |
+      $object.value.pullReplicas | tonumber as $value |
+      {
+        name         : "solr_collections_pull_replicas",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/collections-api.html#clusterstatus",
+        label_names  : ["collection"],
+        label_values : [$collection],
+        value        : $value
+      }
+
+    # solr_collections_nrt_replicas
+    - |-
+      .cluster.collections | to_entries | .[] | . as $object |
+      $object.key as $collection |
+      $object.value.nrtReplicas | tonumber as $value |
+      {
+        name         : "solr_collections_nrt_replicas",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/collections-api.html#clusterstatus",
+        label_names  : ["collection"],
+        label_values : [$collection],
+        value        : $value
+      }
+
+    # solr_collections_tlog_replicas
+    - |-
+      .cluster.collections | to_entries | .[] | . as $object |
+      $object.key as $collection |
+      $object.value.tlogReplicas | tonumber as $value |
+      {
+        name         : "solr_collections_tlog_replicas",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/collections-api.html#clusterstatus",
+        label_names  : ["collection"],
+        label_values : [$collection],
+        value        : $value
+      }
+
+    # solr_collections_shard_state
+    - |-
+      .cluster.collections | to_entries | .[] | . as $object |
+      $object.key as $collection |
+      $object.value.shards | to_entries | .[] | . as $shard_obj |
+      $shard_obj.key as $shard |
+      (if $shard_obj.value.state == "active" then 1.0 else 0.0 end) as $value |
+      {
+        name         : "solr_collections_shard_state",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/collections-api.html#clusterstatus",
+        label_names  : ["collection","shard"],
+        label_values : [$collection,$shard],
+        value        : $value
+      }
+
+    # solr_collections_replica_state
+    - |-
+      .cluster.collections | to_entries | .[] | . as $object |
+      $object.key as $collection |
+      $object.value.shards | to_entries | .[] | . as $shard_obj |
+      $shard_obj.key as $shard |
+      $shard_obj.value.replicas | to_entries | .[] | . as $replica_obj |
+      $replica_obj.key as $replica_name |
+      $replica_obj.value.core as $core |
+      $core[$collection + "_" + $shard + "_" | length:] as $replica |
+      $replica_obj.value.base_url as $base_url |
+      $replica_obj.value.node_name as $node_name |
+      $replica_obj.value.type as $type |
+      (if $replica_obj.value.state == "active" then 1.0 else 0.0 end) as $value |
+      {
+        name         : "solr_collections_replica_state",
+        type         : "GAUGE",
+        help         : "See following URL: https://lucene.apache.org/solr/guide/collections-api.html#clusterstatus",
+        label_names  : ["collection", "shard", "replica", "replica_name", "core", "base_url", "node_name", "type"],
+        label_values : [$collection, $shard, $replica, $replica_name, $core, $base_url, $node_name, $type],
+        value        : $value
+      }
+
+    # solr_collections_shard_leader
+    - |-
+      .cluster.collections | to_entries | .[] | . as $object |
+      $object.key as $collection |
+      $object.value.shards | to_entries | .[] | . as $shard_obj |
+

<TRUNCATED>