diff --git a/src/main/java/io/ebean/meta/MetaInfoManager.java b/src/main/java/io/ebean/meta/MetaInfoManager.java
index b2eaab614..8b38e9786 100644
--- a/src/main/java/io/ebean/meta/MetaInfoManager.java
+++ b/src/main/java/io/ebean/meta/MetaInfoManager.java
@@ -16,6 +16,18 @@ public interface MetaInfoManager {
*/
ServerMetrics collectMetrics();
+ /**
+ * Collect the metrics in raw JSON form.
+ *
{@code
+ *
+ * String metricsJson = database.getMetaInfoManager()
+ * .collectMetricsAsJson()
+ * .json();
+ *
+ * }
+ */
+ ServerMetricsAsJson collectMetricsAsJson();
+
/**
* Collect query plans.
*/
diff --git a/src/main/java/io/ebean/meta/ServerMetricsAsJson.java b/src/main/java/io/ebean/meta/ServerMetricsAsJson.java
new file mode 100644
index 000000000..a85c072cb
--- /dev/null
+++ b/src/main/java/io/ebean/meta/ServerMetricsAsJson.java
@@ -0,0 +1,40 @@
+package io.ebean.meta;
+
+import java.util.Comparator;
+
+/**
+ * Collect the metrics in raw JSON form.
+ */
+public interface ServerMetricsAsJson {
+
+ /**
+ * Set to false to exclude profile location.
+ */
+ ServerMetricsAsJson withLocation(boolean withLocation);
+
+ /**
+ * Set to false to exclude SQL for query metrics.
+ */
+ ServerMetricsAsJson withSql(boolean withSql);
+
+ /**
+ * Set to false to exclude SQL hash.
+ */
+ ServerMetricsAsJson withHash(boolean withHash);
+
+ /**
+ * Set the sort property - see SortMetric
+ * @see SortMetric
+ */
+ ServerMetricsAsJson withSort(Comparator sortBy);
+
+ /**
+ * Set the new line character to use.
+ */
+ ServerMetricsAsJson withNewLine(boolean withNewLine);
+
+ /**
+ * Return the metrics in raw JSON.
+ */
+ String json();
+}
diff --git a/src/main/java/io/ebeaninternal/server/core/DefaultMetaInfoManager.java b/src/main/java/io/ebeaninternal/server/core/DefaultMetaInfoManager.java
index 0c7fe65fa..cc7f101e0 100644
--- a/src/main/java/io/ebeaninternal/server/core/DefaultMetaInfoManager.java
+++ b/src/main/java/io/ebeaninternal/server/core/DefaultMetaInfoManager.java
@@ -12,6 +12,7 @@ import io.ebean.meta.MetaTimedMetric;
import io.ebean.meta.MetricVisitor;
import io.ebean.meta.QueryPlanRequest;
import io.ebean.meta.ServerMetrics;
+import io.ebean.meta.ServerMetricsAsJson;
import java.util.ArrayList;
import java.util.List;
@@ -42,6 +43,11 @@ public class DefaultMetaInfoManager implements MetaInfoManager {
return visitBasic();
}
+ @Override
+ public ServerMetricsAsJson collectMetricsAsJson() {
+ return new DumpMetricsJson(server);
+ }
+
@Override
public BasicMetricVisitor visitBasic() {
BasicMetricVisitor basic = new BasicMetricVisitor();
diff --git a/src/main/java/io/ebeaninternal/server/core/DumpMetricsJson.java b/src/main/java/io/ebeaninternal/server/core/DumpMetricsJson.java
new file mode 100644
index 000000000..11c01149a
--- /dev/null
+++ b/src/main/java/io/ebeaninternal/server/core/DumpMetricsJson.java
@@ -0,0 +1,232 @@
+package io.ebeaninternal.server.core;
+
+import io.ebean.Database;
+import io.ebean.ProfileLocation;
+import io.ebean.meta.MetaCountMetric;
+import io.ebean.meta.MetaOrmQueryMetric;
+import io.ebean.meta.MetaQueryMetric;
+import io.ebean.meta.MetaTimedMetric;
+import io.ebean.meta.ServerMetrics;
+import io.ebean.meta.ServerMetricsAsJson;
+import io.ebean.meta.SortMetric;
+
+import java.io.StringWriter;
+import java.util.Comparator;
+import java.util.List;
+
+class DumpMetricsJson implements ServerMetricsAsJson {
+
+ private final Database database;
+
+ private final StringWriter writer = new StringWriter();
+
+ private boolean dumpHash = true;
+ private boolean dumpSql = true;
+ private boolean dumpLoc = true;
+
+ private Comparator sortBy = SortMetric.NAME;
+
+ private int listCounter;
+ private int objKeyCounter;
+
+ private String newLine = "\n";
+
+ DumpMetricsJson(Database database) {
+ this.database = database;
+ }
+
+ @Override
+ public ServerMetricsAsJson withLocation(boolean withLocation) {
+ this.dumpLoc = withLocation;
+ return this;
+ }
+
+ @Override
+ public ServerMetricsAsJson withSql(boolean withSql) {
+ this.dumpSql = withSql;
+ return this;
+ }
+
+ @Override
+ public ServerMetricsAsJson withHash(boolean withHash) {
+ this.dumpHash = withHash;
+ return this;
+ }
+
+ @Override
+ public ServerMetricsAsJson withSort(Comparator sortBy) {
+ this.sortBy = sortBy;
+ return this;
+ }
+
+ @Override
+ public ServerMetricsAsJson withNewLine(boolean withNewLine) {
+ this.newLine = withNewLine ? "\n" : "";
+ return this;
+ }
+
+ @Override
+ public String json() {
+ collect(database.getMetaInfoManager().collectMetrics());
+ return writer.toString();
+ }
+
+
+ private void collect(ServerMetrics serverMetrics) {
+
+ start();
+ for (MetaTimedMetric metric : serverMetrics.getTimedMetrics()) {
+ log(metric);
+ }
+
+ List countMetrics = serverMetrics.getCountMetrics();
+ if (!countMetrics.isEmpty()) {
+ if (sortBy != null) {
+ countMetrics.sort(SortMetric.COUNT_NAME);
+ }
+ for (MetaCountMetric metric : countMetrics) {
+ logCount(metric);
+ }
+ }
+
+ List ormQueryMetrics = serverMetrics.getOrmQueryMetrics();
+ if (!ormQueryMetrics.isEmpty()) {
+ if (sortBy != null) {
+ ormQueryMetrics.sort(sortBy);
+ }
+ for (MetaOrmQueryMetric metric : ormQueryMetrics) {
+ logQuery(metric);
+ }
+ }
+
+ List dtoQueryMetrics = serverMetrics.getDtoQueryMetrics();
+ if (!dtoQueryMetrics.isEmpty()) {
+ if (sortBy != null) {
+ dtoQueryMetrics.sort(sortBy);
+ }
+ for (MetaQueryMetric metric : dtoQueryMetrics) {
+ logDtoQuery(metric);
+ }
+ }
+ end();
+ }
+
+ private void start() {
+ objStart();
+ key("db");
+ val(database.getName());
+ key("metrics");
+ listStart();
+ }
+
+ private void end() {
+ listEnd();
+ objEnd();
+ }
+
+ private void objStart() {
+ objKeyCounter = 0;
+ writer.append("{");
+ }
+
+ private void objEnd() {
+ writer.append("}");
+ }
+
+ private void listStart() {
+ listCounter = 0;
+ writer.append("[");
+ writer.append(newLine);
+ }
+
+ private void listEnd() {
+ writer.append("]");
+ }
+
+ private void key(String key) {
+ if (objKeyCounter++ > 0) {
+ writer.append(", ");
+ }
+ writer.append("\"").append(key).append("\":");
+ }
+
+ private void val(long count) {
+ writer.append(Long.toString(count));
+ }
+
+ private void val(String val) {
+ writer.append("\"").append(val).append("\"");
+ }
+
+ private void log(MetaTimedMetric metric) {
+
+ metricStart();
+ key("name");
+ val(metric.getName());
+ appendCounters(metric);
+ objEnd();
+ }
+
+ private void metricStart() {
+ if (listCounter++ > 0) {
+ writer.append(",").append(newLine);
+ }
+ objStart();
+ }
+
+ private void logCount(MetaCountMetric metric) {
+ metricStart();
+ key("name");
+ val(metric.getName());
+ key("count");
+ val(metric.getCount());
+ objEnd();
+ }
+
+ private void logQuery(MetaOrmQueryMetric metric) {
+
+ metricStart();
+ key("name");
+ val(metric.getName());
+ appendCounters(metric);
+ if (dumpHash) {
+ key("hash");
+ val(metric.getSqlHash());
+ }
+ appendProfileAndSql(metric);
+ objEnd();
+ }
+
+ private void logDtoQuery(MetaQueryMetric metric) {
+
+ metricStart();
+ key("name");
+ val(metric.getName());
+ appendCounters(metric);
+ appendProfileAndSql(metric);
+ objEnd();
+ }
+
+ private void appendProfileAndSql(MetaQueryMetric metric) {
+ ProfileLocation profileLocation = metric.getProfileLocation();
+ if (dumpLoc && profileLocation != null) {
+ key("loc");
+ val(profileLocation.shortDescription());
+ }
+ if (dumpSql) {
+ key("sql");
+ val(metric.getSql());
+ }
+ }
+
+ private void appendCounters(MetaTimedMetric timedMetric) {
+ key("count");
+ val(timedMetric.getCount());
+ key("total");
+ val(timedMetric.getTotal());
+ key("mean");
+ val(timedMetric.getMean());
+ key("max");
+ val(timedMetric.getMax());
+ }
+}
diff --git a/src/test/java/org/tests/query/finder/TestCustomerFinder.java b/src/test/java/org/tests/query/finder/TestCustomerFinder.java
index b06bd8e69..7ab664a09 100644
--- a/src/test/java/org/tests/query/finder/TestCustomerFinder.java
+++ b/src/test/java/org/tests/query/finder/TestCustomerFinder.java
@@ -8,6 +8,7 @@ import io.ebean.meta.MetaQueryPlan;
import io.ebean.meta.MetaTimedMetric;
import io.ebean.meta.QueryPlanRequest;
import io.ebean.meta.ServerMetrics;
+import io.ebean.meta.SortMetric;
import org.ebeantest.LoggedSqlCollector;
import org.junit.Test;
import org.tests.model.basic.Customer;
@@ -138,20 +139,7 @@ public class TestCustomerFinder extends BaseTestCase {
ResetBasicData.reset();
- resetAllMetrics();
-
- List customers = Customer.find.all();
- assertThat(customers).isNotEmpty();
-
- Customer customer = Customer.find.byId(1);
- assertThat(customer).isNotNull();
- Customer.find.byId(2);
-
- Customer.find.namesStartingWith("F");
- Customer.find.byNameStatus("Rob", Customer.Status.ACTIVE);
- Customer.find.totalCount();
- Customer.find.updateNames("Junk", 2000);
- Customer.find.byId(3);
+ runQueries();
ServerMetrics metrics = server().getMetaInfoManager().collectMetrics();
@@ -172,7 +160,71 @@ public class TestCustomerFinder extends BaseTestCase {
for (MetaQueryPlan plan : plans) {
System.out.println(plan);
}
+ }
+ @Test
+ public void test_metricsAsJson_withAll() {
+
+ ResetBasicData.reset();
+
+ runQueries();
+
+ String metricsJson = server().getMetaInfoManager()
+ .collectMetricsAsJson()
+ .withHash(true)
+ .withLocation(true)
+ .withNewLine(true)
+ .withSql(true)
+ .withSort(SortMetric.TOTAL)
+ .json();
+
+ System.out.println(metricsJson);
+ assertThat(metricsJson).contains("\"name\":\"txn.main\"");
+ assertThat(metricsJson).contains("\"name\":\"Customer.findList\"");
+ assertThat(metricsJson).contains("\"loc\":\"CustomerFinder.byNameStatus(CustomerFinder.java:44)\"");
+ assertThat(metricsJson).contains("\"hash\":\"4d648ce0542aedfb042ad68746342730\"");
+ assertThat(metricsJson).contains("\"sql\":\"select t0.id, t0.status,");
+ }
+
+ @Test
+ public void test_metricsAsJson_minimal() {
+
+ ResetBasicData.reset();
+
+ runQueries();
+
+ String metricsJson = server().getMetaInfoManager()
+ .collectMetricsAsJson()
+ .withHash(false)
+ .withLocation(false)
+ .withNewLine(false)
+ .withSql(false)
+ .withSort(null)
+ .json();
+
+ System.out.println(metricsJson);
+ assertThat(metricsJson).contains("\"name\":\"txn.main\"");
+ assertThat(metricsJson).contains("\"name\":\"Customer.findList\"");
+ assertThat(metricsJson).doesNotContain("\"loc\":");
+ assertThat(metricsJson).doesNotContain("\"hash\":");
+ assertThat(metricsJson).doesNotContain("\"sql\":");
+ }
+
+ private void runQueries() {
+ resetAllMetrics();
+
+ List customers = Customer.find.all();
+ assertThat(customers).isNotEmpty();
+
+ Customer customer = Customer.find.byId(1);
+ assertThat(customer).isNotNull();
+ Customer.find.byId(2);
+
+ Customer.find.namesStartingWith("F");
+ Customer.find.byNameStatus("Rob", Customer.Status.ACTIVE);
+ Customer.find.totalCount();
+ Customer.find.updateNames("Junk", 2000);
+ Customer.find.byId(3);
}
}