From 4af8e533151868f404c7e5ee8a29504276c106a1 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Tue, 9 Apr 2019 22:54:16 +1200 Subject: [PATCH] #1670 - Expose metrics as ServerMetrics interface (improvement over existing BasicMetricVisitor use) --- .../io/ebean/meta/BasicMetricVisitor.java | 5 +- .../java/io/ebean/meta/MetaInfoManager.java | 9 +++ .../java/io/ebean/meta/ServerMetrics.java | 24 +++++++ .../server/core/DefaultMetaInfoManager.java | 6 ++ src/test/java/io/ebean/BaseTestCase.java | 8 +-- .../java/io/ebean/DtoQueryFromOrmTest.java | 64 +++++++++---------- src/test/java/io/ebean/DtoQueryTest.java | 7 +- src/test/java/io/ebean/UpdateQueryTest.java | 10 +-- .../batchinsert/TestBatchInsertFlush.java | 6 +- .../query/finder/TestCustomerFinder.java | 8 +-- 10 files changed, 95 insertions(+), 52 deletions(-) create mode 100644 src/main/java/io/ebean/meta/ServerMetrics.java diff --git a/src/main/java/io/ebean/meta/BasicMetricVisitor.java b/src/main/java/io/ebean/meta/BasicMetricVisitor.java index bef165ed9..bc1658a02 100644 --- a/src/main/java/io/ebean/meta/BasicMetricVisitor.java +++ b/src/main/java/io/ebean/meta/BasicMetricVisitor.java @@ -6,7 +6,7 @@ import java.util.List; /** * A simple MetricVisitor that can collect the desired metrics into lists. */ -public class BasicMetricVisitor extends AbstractMetricVisitor { +public class BasicMetricVisitor extends AbstractMetricVisitor implements ServerMetrics { private final List timed = new ArrayList<>(); private final List dtoQuery = new ArrayList<>(); @@ -29,6 +29,7 @@ public class BasicMetricVisitor extends AbstractMetricVisitor { /** * Return timed metrics for Transactions, labelled SqlQuery, labelled SqlUpdate. */ + @Override public List getTimedMetrics() { return timed; } @@ -36,6 +37,7 @@ public class BasicMetricVisitor extends AbstractMetricVisitor { /** * Return the DTO query metrics. */ + @Override public List getDtoQueryMetrics() { return dtoQuery; } @@ -43,6 +45,7 @@ public class BasicMetricVisitor extends AbstractMetricVisitor { /** * Return the ORM query metrics. */ + @Override public List getOrmQueryMetrics() { return ormQuery; } diff --git a/src/main/java/io/ebean/meta/MetaInfoManager.java b/src/main/java/io/ebean/meta/MetaInfoManager.java index a1638b6be..b2eaab614 100644 --- a/src/main/java/io/ebean/meta/MetaInfoManager.java +++ b/src/main/java/io/ebean/meta/MetaInfoManager.java @@ -7,6 +7,15 @@ import java.util.List; */ public interface MetaInfoManager { + /** + * Return the metrics for the database instance. + *

+ * This will reset the metrics (reset counters back to zero etc) and + * will only return the non-empty metrics. + *

+ */ + ServerMetrics collectMetrics(); + /** * Collect query plans. */ diff --git a/src/main/java/io/ebean/meta/ServerMetrics.java b/src/main/java/io/ebean/meta/ServerMetrics.java new file mode 100644 index 000000000..8b556eb51 --- /dev/null +++ b/src/main/java/io/ebean/meta/ServerMetrics.java @@ -0,0 +1,24 @@ +package io.ebean.meta; + +import java.util.List; + +/** + * Metrics of the Database instance. + */ +public interface ServerMetrics { + + /** + * Return timed metrics for Transactions, labelled SqlQuery, labelled SqlUpdate. + */ + List getTimedMetrics(); + + /** + * Return the DTO query metrics. + */ + List getDtoQueryMetrics(); + + /** + * Return the ORM query metrics. + */ + List getOrmQueryMetrics(); +} diff --git a/src/main/java/io/ebeaninternal/server/core/DefaultMetaInfoManager.java b/src/main/java/io/ebeaninternal/server/core/DefaultMetaInfoManager.java index 377ccb081..2b3c13dc2 100644 --- a/src/main/java/io/ebeaninternal/server/core/DefaultMetaInfoManager.java +++ b/src/main/java/io/ebeaninternal/server/core/DefaultMetaInfoManager.java @@ -10,6 +10,7 @@ import io.ebean.meta.MetaQueryPlan; import io.ebean.meta.MetaTimedMetric; import io.ebean.meta.MetricVisitor; import io.ebean.meta.QueryPlanRequest; +import io.ebean.meta.ServerMetrics; import java.util.ArrayList; import java.util.List; @@ -35,6 +36,11 @@ public class DefaultMetaInfoManager implements MetaInfoManager { server.visitMetrics(visitor); } + @Override + public ServerMetrics collectMetrics() { + return visitBasic(); + } + @Override public BasicMetricVisitor visitBasic() { BasicMetricVisitor basic = new BasicMetricVisitor(); diff --git a/src/test/java/io/ebean/BaseTestCase.java b/src/test/java/io/ebean/BaseTestCase.java index 96b661c11..7f0577c5b 100644 --- a/src/test/java/io/ebean/BaseTestCase.java +++ b/src/test/java/io/ebean/BaseTestCase.java @@ -2,9 +2,9 @@ package io.ebean; import io.ebean.annotation.PersistBatch; import io.ebean.annotation.Platform; -import io.ebean.meta.BasicMetricVisitor; import io.ebean.meta.MetaTimedMetric; import io.ebean.meta.MetricType; +import io.ebean.meta.ServerMetrics; import io.ebean.util.StringHelper; import io.ebeaninternal.api.SpiEbeanServer; import io.ebeaninternal.api.SpiQuery; @@ -64,12 +64,12 @@ public abstract class BaseTestCase { server().getMetaInfoManager().resetAllMetrics(); } - protected BasicMetricVisitor visitMetricsBasic() { - return server().getMetaInfoManager().visitBasic(); + protected ServerMetrics collectMetrics() { + return server().getMetaInfoManager().collectMetrics(); } protected List visitTimedMetrics() { - return visitMetricsBasic().getTimedMetrics(); + return collectMetrics().getTimedMetrics(); } protected List sqlMetrics() { diff --git a/src/test/java/io/ebean/DtoQueryFromOrmTest.java b/src/test/java/io/ebean/DtoQueryFromOrmTest.java index d551a9807..793d69720 100644 --- a/src/test/java/io/ebean/DtoQueryFromOrmTest.java +++ b/src/test/java/io/ebean/DtoQueryFromOrmTest.java @@ -2,9 +2,9 @@ package io.ebean; import io.ebean.annotation.ForPlatform; import io.ebean.annotation.Platform; -import io.ebean.meta.BasicMetricVisitor; import io.ebean.meta.MetaQueryMetric; import io.ebean.meta.MetaTimedMetric; +import io.ebean.meta.ServerMetrics; import org.ebeantest.LoggedSqlCollector; import org.junit.AfterClass; import org.junit.BeforeClass; @@ -25,13 +25,13 @@ public class DtoQueryFromOrmTest extends BaseTestCase { @AfterClass public static void reportStats() { - BasicMetricVisitor basic = DB.getDefault().getMetaInfoManager().visitBasic(); - for (MetaQueryMetric metric : basic.getDtoQueryMetrics()) { + ServerMetrics metrics = DB.getDefault().getMetaInfoManager().collectMetrics(); + for (MetaQueryMetric metric : metrics.getDtoQueryMetrics()) { System.out.println(metric); } System.out.println("-- transaction metrics --"); - for (MetaTimedMetric metric : basic.getTimedMetrics()) { + for (MetaTimedMetric metric : metrics.getTimedMetrics()) { System.out.println(metric); } } @@ -44,19 +44,19 @@ public class DtoQueryFromOrmTest extends BaseTestCase { resetAllMetrics(); - String[] prefix = { "Bl", "B", "Red", "jim" }; + String[] prefix = {"Bl", "B", "Red", "jim"}; for (String val : prefix) { DB.find(Contact.class) - .select("email, " + concat("lastName", ", ", "firstName") + " as fullName").where() - .istartsWith(concat("lastName", ", ", "firstName"), val).orderBy().asc("lastName").setMaxRows(10) - .asDto(ContactDto.class).setLabel("prefixLoop").findList(); + .select("email, " + concat("lastName", ", ", "firstName") + " as fullName").where() + .istartsWith(concat("lastName", ", ", "firstName"), val).orderBy().asc("lastName").setMaxRows(10) + .asDto(ContactDto.class).setLabel("prefixLoop").findList(); } - BasicMetricVisitor basic = visitMetricsBasic(); + ServerMetrics metrics = collectMetrics(); - List stats = basic.getDtoQueryMetrics(); + List stats = metrics.getDtoQueryMetrics(); for (MetaQueryMetric stat : stats) { long meanMicros = stat.getMean(); assertThat(meanMicros).isLessThan(900_000); @@ -74,10 +74,10 @@ public class DtoQueryFromOrmTest extends BaseTestCase { LoggedSqlCollector.start(); DtoQuery query = DB.find(Contact.class) - // we must explicitly add the id property for DTO query (if we want it) - .select("id, email, " + concat("lastName", ", ", "firstName") + " as fullName").where().isNotNull("email") - .isNotNull("lastName").orderBy().asc("lastName").asDto(ContactDto.class).setLabel("explicitId") - .setRelaxedMode(); + // we must explicitly add the id property for DTO query (if we want it) + .select("id, email, " + concat("lastName", ", ", "firstName") + " as fullName").where().isNotNull("email") + .isNotNull("lastName").orderBy().asc("lastName").asDto(ContactDto.class).setLabel("explicitId") + .setRelaxedMode(); List dtos = query.findList(); @@ -90,7 +90,7 @@ public class DtoQueryFromOrmTest extends BaseTestCase { List sql = LoggedSqlCollector.stop(); assertThat(sql.get(0)).contains("select t0.id, t0.email, " + concat("t0.last_name", ", ", "t0.first_name") - + " fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name"); + + " fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name"); } @Test @@ -101,8 +101,8 @@ public class DtoQueryFromOrmTest extends BaseTestCase { LoggedSqlCollector.start(); DtoQuery query = DB.find(Contact.class) - .select("email, " + concat("lastName", ", ", "firstName") + " as fullName").where().isNotNull("email") - .isNotNull("lastName").orderBy().asc("lastName").asDto(ContactDto.class); + .select("email, " + concat("lastName", ", ", "firstName") + " as fullName").where().isNotNull("email") + .isNotNull("lastName").orderBy().asc("lastName").asDto(ContactDto.class); List dtos = query.findList(); @@ -115,7 +115,7 @@ public class DtoQueryFromOrmTest extends BaseTestCase { List sql = LoggedSqlCollector.stop(); assertThat(sql.get(0)).contains("select t0.email, " + concat("t0.last_name", ", ", "t0.first_name") - + " fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name"); + + " fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name"); } @Test @@ -126,8 +126,8 @@ public class DtoQueryFromOrmTest extends BaseTestCase { LoggedSqlCollector.start(); List contactDtos = DB.find(Contact.class).setLabel("emailFullName") - .select("email, " + concat("lastName", ", ", "firstName") + " as fullName").where().isNotNull("email") - .isNotNull("lastName").orderBy().asc("lastName").setMaxRows(10).asDto(ContactDto.class).findList(); + .select("email, " + concat("lastName", ", ", "firstName") + " as fullName").where().isNotNull("email") + .isNotNull("lastName").orderBy().asc("lastName").setMaxRows(10).asDto(ContactDto.class).findList(); assertThat(contactDtos).isNotEmpty(); @@ -140,11 +140,11 @@ public class DtoQueryFromOrmTest extends BaseTestCase { if (isSqlServer()) { assertThat(sql.get(0)).contains("select top 10 t0.email, " + concat("t0.last_name", ", ", "t0.first_name") - + " fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name"); + + " fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name"); } else { assertThat(sql.get(0)).contains("select t0.email, " + concat("t0.last_name", ", ", "t0.first_name") - + " fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name"); + + " fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name"); } } @@ -156,8 +156,8 @@ public class DtoQueryFromOrmTest extends BaseTestCase { LoggedSqlCollector.start(); List contactDtos = DB.find(Contact.class) - .select("id, email, " + concat("lastName", ", ", "firstName") + " as fullName").where().isNotNull("email") - .isNotNull("lastName").orderBy().asc("lastName").setMaxRows(10).asDto(ContactDto.class).findList(); + .select("id, email, " + concat("lastName", ", ", "firstName") + " as fullName").where().isNotNull("email") + .isNotNull("lastName").orderBy().asc("lastName").setMaxRows(10).asDto(ContactDto.class).findList(); assertThat(contactDtos).isNotEmpty(); @@ -170,11 +170,11 @@ public class DtoQueryFromOrmTest extends BaseTestCase { List sql = LoggedSqlCollector.stop(); if (isSqlServer()) { assertThat(sql.get(0)).contains("select top 10 t0.id, t0.email, " - + concat("t0.last_name", ", ", "t0.first_name") - + " fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name"); + + concat("t0.last_name", ", ", "t0.first_name") + + " fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name"); } else { assertThat(sql.get(0)).contains("select t0.id, t0.email, " + concat("t0.last_name", ", ", "t0.first_name") - + " fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name"); + + " fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name"); } } @@ -186,8 +186,8 @@ public class DtoQueryFromOrmTest extends BaseTestCase { LoggedSqlCollector.start(); List contactDtos = DB.find(Contact.class) - .select(concat("lastName", ", ", "firstName") + " as fullName").where().isNotNull("lastName").orderBy() - .asc("lastName").asDto(ContactDto.class).setFirstRow(2).setMaxRows(5).findList(); + .select(concat("lastName", ", ", "firstName") + " as fullName").where().isNotNull("lastName").orderBy() + .asc("lastName").asDto(ContactDto.class).setFirstRow(2).setMaxRows(5).findList(); assertThat(contactDtos).isNotEmpty(); @@ -209,8 +209,8 @@ public class DtoQueryFromOrmTest extends BaseTestCase { LoggedSqlCollector.start(); List contactDtos = DB.find(Contact.class).select("lastName, count(*) as totalCount").where() - .isNotNull("lastName").having().gt("count(*)", 1).orderBy().desc("count(*)").asDto(ContactTotals.class) - .findList(); + .isNotNull("lastName").having().gt("count(*)", 1).orderBy().desc("count(*)").asDto(ContactTotals.class) + .findList(); assertThat(contactDtos).isNotEmpty(); @@ -229,7 +229,7 @@ public class DtoQueryFromOrmTest extends BaseTestCase { ResetBasicData.reset(); List contactDtos = DB.find(Contact.class).select("lastName, count(*) as totalCount").where() - .isNotNull("lastName").asDto(ContactTotals.class).findList(); + .isNotNull("lastName").asDto(ContactTotals.class).findList(); assertThat(contactDtos).isNotEmpty(); } diff --git a/src/test/java/io/ebean/DtoQueryTest.java b/src/test/java/io/ebean/DtoQueryTest.java index a1f20ba16..fd3c20711 100644 --- a/src/test/java/io/ebean/DtoQueryTest.java +++ b/src/test/java/io/ebean/DtoQueryTest.java @@ -4,6 +4,7 @@ import io.ebean.annotation.ForPlatform; import io.ebean.annotation.Platform; import io.ebean.meta.BasicMetricVisitor; import io.ebean.meta.MetaQueryMetric; +import io.ebean.meta.ServerMetrics; import org.ebeantest.LoggedSqlCollector; import org.junit.Test; import org.slf4j.Logger; @@ -33,9 +34,9 @@ public class DtoQueryTest extends BaseTestCase { log.info(list.toString()); assertThat(list).isNotEmpty(); - BasicMetricVisitor basic = visitMetricsBasic(); + ServerMetrics metrics = collectMetrics(); - List stats = basic.getDtoQueryMetrics(); + List stats = metrics.getDtoQueryMetrics(); for (MetaQueryMetric stat : stats) { long meanMicros = stat.getMean(); assertThat(meanMicros).isLessThan(900_000); @@ -208,7 +209,7 @@ public class DtoQueryTest extends BaseTestCase { .setParameter("name", "rob") .findList(); - BasicMetricVisitor metric2 = server().getMetaInfoManager().visitBasic(); + ServerMetrics metric2 = server().getMetaInfoManager().collectMetrics(); stats = metric2.getDtoQueryMetrics(); assertThat(stats).hasSize(2); diff --git a/src/test/java/io/ebean/UpdateQueryTest.java b/src/test/java/io/ebean/UpdateQueryTest.java index 0a078d26b..cfbdb02f6 100644 --- a/src/test/java/io/ebean/UpdateQueryTest.java +++ b/src/test/java/io/ebean/UpdateQueryTest.java @@ -2,8 +2,8 @@ package io.ebean; import io.ebean.annotation.IgnorePlatform; import io.ebean.annotation.Platform; -import io.ebean.meta.BasicMetricVisitor; import io.ebean.meta.MetaOrmQueryMetric; +import io.ebean.meta.ServerMetrics; import org.ebeantest.LoggedSqlCollector; import org.junit.Test; import org.tests.model.basic.Country; @@ -38,8 +38,8 @@ public class UpdateQueryTest extends BaseTestCase { assertThat(query.getGeneratedSql()).contains("update o_customer set status=?, updtime=? where status = ? and id > ?"); - BasicMetricVisitor basic = visitMetricsBasic(); - List ormQueryMetrics = basic.getOrmQueryMetrics(); + ServerMetrics metrics = collectMetrics(); + List ormQueryMetrics = metrics.getOrmQueryMetrics(); assertThat(ormQueryMetrics).hasSize(1); assertThat(ormQueryMetrics.get(0).getType()).isEqualTo(Customer.class); assertThat(ormQueryMetrics.get(0).getLabel()).isEqualTo("updateActive"); @@ -68,8 +68,8 @@ public class UpdateQueryTest extends BaseTestCase { assertThat(sql.get(0)).contains("update o_customer set status = status"); - BasicMetricVisitor basic = visitMetricsBasic(); - List ormQueryMetrics = basic.getOrmQueryMetrics(); + ServerMetrics metrics = collectMetrics(); + List ormQueryMetrics = metrics.getOrmQueryMetrics(); assertThat(ormQueryMetrics).hasSize(1); assertThat(ormQueryMetrics.get(0).getType()).isEqualTo(Customer.class); assertThat(ormQueryMetrics.get(0).getLabel()).isEqualTo("updateAll"); diff --git a/src/test/java/org/tests/batchinsert/TestBatchInsertFlush.java b/src/test/java/org/tests/batchinsert/TestBatchInsertFlush.java index 64d0364d1..86ee256bd 100644 --- a/src/test/java/org/tests/batchinsert/TestBatchInsertFlush.java +++ b/src/test/java/org/tests/batchinsert/TestBatchInsertFlush.java @@ -8,8 +8,8 @@ import io.ebean.annotation.IgnorePlatform; import io.ebean.annotation.PersistBatch; import io.ebean.annotation.Platform; import io.ebean.annotation.Transactional; -import io.ebean.meta.BasicMetricVisitor; import io.ebean.meta.MetaTimedMetric; +import io.ebean.meta.ServerMetrics; import io.ebeaninternal.api.SpiTransaction; import org.ebeantest.LoggedSqlCollector; import org.junit.Test; @@ -77,8 +77,8 @@ public class TestBatchInsertFlush extends BaseTestCase { transaction.end(); } - BasicMetricVisitor basic = visitMetricsBasic(); - List txnStats = basic.getTimedMetrics(); + ServerMetrics metrics = collectMetrics(); + List txnStats = metrics.getTimedMetrics(); for (MetaTimedMetric txnMetric : txnStats) { System.out.println(txnMetric); } diff --git a/src/test/java/org/tests/query/finder/TestCustomerFinder.java b/src/test/java/org/tests/query/finder/TestCustomerFinder.java index 26c2f1b4c..b06bd8e69 100644 --- a/src/test/java/org/tests/query/finder/TestCustomerFinder.java +++ b/src/test/java/org/tests/query/finder/TestCustomerFinder.java @@ -3,11 +3,11 @@ package org.tests.query.finder; import io.ebean.BaseTestCase; import io.ebean.Ebean; import io.ebean.Transaction; -import io.ebean.meta.BasicMetricVisitor; import io.ebean.meta.MetaOrmQueryMetric; import io.ebean.meta.MetaQueryPlan; import io.ebean.meta.MetaTimedMetric; import io.ebean.meta.QueryPlanRequest; +import io.ebean.meta.ServerMetrics; import org.ebeantest.LoggedSqlCollector; import org.junit.Test; import org.tests.model.basic.Customer; @@ -153,16 +153,16 @@ public class TestCustomerFinder extends BaseTestCase { Customer.find.updateNames("Junk", 2000); Customer.find.byId(3); - BasicMetricVisitor basic = server().getMetaInfoManager().visitBasic(); + ServerMetrics metrics = server().getMetaInfoManager().collectMetrics(); - List planStats = basic.getOrmQueryMetrics(); + List planStats = metrics.getOrmQueryMetrics(); assertThat(planStats.size()).isGreaterThan(4); for (MetaOrmQueryMetric planStat : planStats) { System.out.println(planStat); } - for (MetaTimedMetric txnTimed : basic.getTimedMetrics()) { + for (MetaTimedMetric txnTimed : metrics.getTimedMetrics()) { System.out.println(txnTimed); }