From 9ee6cf7f905010fbf230c7c534a493cb5738e6a6 Mon Sep 17 00:00:00 2001 From: Jim Ewald Date: Fri, 27 Jan 2017 11:30:15 -0800 Subject: [PATCH 1/7] Update depricated fields with their respective replacements. --- .../blocklyprop/utils/HttpServletRequestImpl.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/parallax/server/blocklyprop/utils/HttpServletRequestImpl.java b/src/main/java/com/parallax/server/blocklyprop/utils/HttpServletRequestImpl.java index a51703bf..7255be5e 100644 --- a/src/main/java/com/parallax/server/blocklyprop/utils/HttpServletRequestImpl.java +++ b/src/main/java/com/parallax/server/blocklyprop/utils/HttpServletRequestImpl.java @@ -152,9 +152,12 @@ public boolean isRequestedSessionIdFromURL() { throw new UnsupportedOperationException("Not supported."); } + /* + * Depricated as of Java Servlet API version 2.1 + */ @Override public boolean isRequestedSessionIdFromUrl() { - throw new UnsupportedOperationException("Not supported."); + return this.isRequestedSessionIdFromURL(); } @Override @@ -277,9 +280,16 @@ public RequestDispatcher getRequestDispatcher(String path) { throw new UnsupportedOperationException("Not supported."); } + /* + * Depricated as of Java Servlet API version 2.1 + * + * Consider using this in it's place: + * + * servletRequest.getSession().getServletContext().getRealPath("/") + */ @Override public String getRealPath(String path) { - throw new UnsupportedOperationException("Not supported."); + return this.getSession().getServletContext().getRealPath(path); } @Override From 88486a01165440e38cb067d4fc4d9c4406f2f647 Mon Sep 17 00:00:00 2001 From: Jim Ewald Date: Fri, 27 Jan 2017 13:03:12 -0800 Subject: [PATCH 2/7] POM update to import logback logger. Update implementation classes to support logging. --- pom.xml | 14 ++++++++++++++ .../blocklyprop/db/dao/impl/ProjectDaoImpl.java | 4 +++- .../blocklyprop/db/dao/impl/UserDaoImpl.java | 2 +- src/main/resources/logback.xml | 16 ++++++++++++++++ 4 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 src/main/resources/logback.xml diff --git a/pom.xml b/pom.xml index ec0b6a33..204a5830 100644 --- a/pom.xml +++ b/pom.xml @@ -238,11 +238,25 @@ slf4j-api 1.7.21 + + + ch.qos.logback + logback-classic + 1.1.8 + + + ch.qos.logback + logback-core + 1.1.8 + + + diff --git a/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/ProjectDaoImpl.java b/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/ProjectDaoImpl.java index ed9a0255..66ff8224 100644 --- a/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/ProjectDaoImpl.java +++ b/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/ProjectDaoImpl.java @@ -20,6 +20,8 @@ import org.jooq.Condition; import org.jooq.DSLContext; import org.jooq.SortField; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * @@ -27,7 +29,7 @@ */ @Singleton public class ProjectDaoImpl implements ProjectDao { - + private static final Logger LOG = LoggerFactory.getLogger(ProjectDao.class); private DSLContext create; @Inject diff --git a/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/UserDaoImpl.java b/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/UserDaoImpl.java index 983d5934..6004370c 100644 --- a/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/UserDaoImpl.java +++ b/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/UserDaoImpl.java @@ -29,7 +29,7 @@ @Singleton public class UserDaoImpl implements UserDao { - private static Logger log = LoggerFactory.getLogger(UserDao.class); + private static final Logger log = LoggerFactory.getLogger(UserDao.class); private DSLContext create; diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 00000000..94912db1 --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,16 @@ + + + + + + + + + + From cb0b22113d5a51628bbd4e4953136126ed9163ab Mon Sep 17 00:00:00 2001 From: Jim Ewald Date: Sat, 28 Jan 2017 22:22:07 -0800 Subject: [PATCH 3/7] Enable logging to a file. Created two loggers to support JVM monitoring and application monitoring. --- pom.xml | 18 ++++++- .../blocklyprop/config/SetupConfig.java | 18 ++++++- .../db/dao/impl/ProjectDaoImpl.java | 2 + .../blocklyprop/monitoring/Monitor.java | 50 +++++++++++++++---- src/main/resources/logback.xml | 30 ++++++++++- src/test/resources/logback-test.xml | 25 ++++++++++ 6 files changed, 128 insertions(+), 15 deletions(-) create mode 100644 src/test/resources/logback-test.xml diff --git a/pom.xml b/pom.xml index 204a5830..703dc3ee 100644 --- a/pom.xml +++ b/pom.xml @@ -403,10 +403,17 @@ net.kencochrane.raven - raven-log4j + raven-logback 6.0.0 + org.apache.lucene @@ -453,12 +460,19 @@ ${metrics-version} + + io.dropwizard.metrics + metrics-logback + 3.1.2 + + + io.dropwizard.metrics metrics-servlet diff --git a/src/main/java/com/parallax/server/blocklyprop/config/SetupConfig.java b/src/main/java/com/parallax/server/blocklyprop/config/SetupConfig.java index b305c0f5..f442be35 100644 --- a/src/main/java/com/parallax/server/blocklyprop/config/SetupConfig.java +++ b/src/main/java/com/parallax/server/blocklyprop/config/SetupConfig.java @@ -21,6 +21,10 @@ import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.DefaultConfigurationBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import ch.qos.logback.classic.LoggerContext; + /** * @@ -29,6 +33,7 @@ public class SetupConfig extends GuiceServletContextListener { private Configuration configuration; + private final Logger LOG = LoggerFactory.getLogger(this.getClass()); @Override protected Injector getInjector() { @@ -62,10 +67,11 @@ protected void configure() { private void readConfiguration() { try { - System.out.println("Looking for blocklyprop.properties in: " + System.getProperty("user.home")); + LOG.info("Looking for blocklyprop.properties in: {}", System.getProperty("user.home")); DefaultConfigurationBuilder configurationBuilder = new DefaultConfigurationBuilder(getClass().getResource("/config.xml")); configuration = configurationBuilder.getConfiguration(); } catch (ConfigurationException ce) { + LOG.error("{}", ce.getMessage()); ce.printStackTrace(); } catch (Throwable t) { t.printStackTrace(); @@ -81,12 +87,20 @@ public void contextDestroyed(ServletContextEvent servletContextEvent) { Driver driver = drivers.nextElement(); try { DriverManager.deregisterDriver(driver); - // LOG.log(Level.INFO, String.format("deregistering jdbc driver: %s", driver)); + LOG.info("deregistering jdbc driver: {}",driver); } catch (SQLException sqlE) { // LOG.log(Level.SEVERE, String.format("Error deregistering driver %s", driver), e); } } + + // Shut down the loggers. Assume SLF4J is bound to logback-classic + // in the current environment + LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory(); + if (loggerContext != null) { + loggerContext.stop(); + } + } } diff --git a/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/ProjectDaoImpl.java b/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/ProjectDaoImpl.java index 66ff8224..3fb88f2c 100644 --- a/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/ProjectDaoImpl.java +++ b/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/ProjectDaoImpl.java @@ -39,9 +39,11 @@ public void setDSLContext(DSLContext dsl) { // Swap out old block definitions private ProjectRecord alterReadRecord(ProjectRecord record) { + LOG.info("Updating outdated block definitions"); String newCode; if (record == null) { + LOG.error("Null project record detected."); throw new NullPointerException("Cannot alter a null project record."); } diff --git a/src/main/java/com/parallax/server/blocklyprop/monitoring/Monitor.java b/src/main/java/com/parallax/server/blocklyprop/monitoring/Monitor.java index 909ce416..c61ec60b 100644 --- a/src/main/java/com/parallax/server/blocklyprop/monitoring/Monitor.java +++ b/src/main/java/com/parallax/server/blocklyprop/monitoring/Monitor.java @@ -12,17 +12,23 @@ import com.codahale.metrics.graphite.PickledGraphite; import com.codahale.metrics.jvm.GarbageCollectorMetricSet; import com.codahale.metrics.jvm.MemoryUsageGaugeSet; -import com.codahale.metrics.log4j.InstrumentedAppender; +import com.codahale.metrics.Slf4jReporter; +// import com.codahale.metrics.log4j.InstrumentedAppender; +// import com.codahale.metrics.logback.InstrumentedAppender; import com.google.inject.Inject; import com.google.inject.Singleton; import java.net.InetSocketAddress; +// import java.util.HashSet; import java.util.concurrent.TimeUnit; import org.apache.commons.configuration.Configuration; -import org.apache.log4j.LogManager; +import org.slf4j.LoggerFactory; + + /** * * @author Michel + * */ @Singleton public class Monitor { @@ -40,6 +46,7 @@ public class Monitor { @Inject public Monitor(Configuration configuration) { + /* Load settings from the application configuration file */ consoleEnabled = configuration.getBoolean("monitor.console.enabled", false); consoleReportingInterval = configuration.getInt("monitor.console.interval", 300); @@ -53,21 +60,46 @@ public Monitor(Configuration configuration) { } private void init() { + +// final LoggerContext factory = (LoggerContext) LoggerFactory.getILoggerFactory(); + if (consoleEnabled) { - ConsoleReporter reporter = ConsoleReporter.forRegistry(metrics).convertDurationsTo(TimeUnit.MILLISECONDS).build(); + ConsoleReporter reporter = + ConsoleReporter + .forRegistry(metrics) + .convertDurationsTo(TimeUnit.MILLISECONDS) + .build(); reporter.start(consoleReportingInterval, TimeUnit.SECONDS); } if (graphiteEnabled) { - final PickledGraphite pickledGraphite = new PickledGraphite(new InetSocketAddress(graphiteServerAddress, graphiteServerPort)); - final GraphiteReporter graphiteReporter = GraphiteReporter.forRegistry(metrics).prefixedWith(graphitePrefix).convertDurationsTo(TimeUnit.MILLISECONDS).filter(MetricFilter.ALL).build(pickledGraphite); + final PickledGraphite pickledGraphite = new PickledGraphite( + new InetSocketAddress( + graphiteServerAddress, + graphiteServerPort)); + final GraphiteReporter graphiteReporter = + GraphiteReporter + .forRegistry(metrics) + .prefixedWith(graphitePrefix) + .convertDurationsTo(TimeUnit.MILLISECONDS). + filter(MetricFilter.ALL).build(pickledGraphite); graphiteReporter.start(graphiteReportingInterval, TimeUnit.SECONDS); } + + final Slf4jReporter reporter = Slf4jReporter + .forRegistry(metrics) + .outputTo(LoggerFactory.getLogger(Monitor.class)) + .convertRatesTo(TimeUnit.SECONDS) + .convertDurationsTo(TimeUnit.MILLISECONDS) + .build(); + reporter.start(5, TimeUnit.SECONDS); - InstrumentedAppender appender = new InstrumentedAppender(metrics); - appender.activateOptions(); - - LogManager.getRootLogger().addAppender(appender); +// InstrumentedAppender appender = new InstrumentedAppender(metrics); +// appender.setContext(context); + +// appender.activateOptions(); + +// LogManager.getRootLogger().addAppender(appender); MemoryUsageGaugeSet memoryUsageGaugeSet = new MemoryUsageGaugeSet(); metrics.registerAll(memoryUsageGaugeSet); diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml index 94912db1..ae2759e8 100644 --- a/src/main/resources/logback.xml +++ b/src/main/resources/logback.xml @@ -9,8 +9,34 @@ and open the template in the editor. Valid logging levels: TRACE, DEBUG, INFO, WARN and ERROR --> + + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + /home/developer/blockly-app.log + + %date %level [%thread] %logger{10} [%file:%line] %msg%n + + - - + + + + + + + + + + + diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml new file mode 100644 index 00000000..9ab4db8a --- /dev/null +++ b/src/test/resources/logback-test.xml @@ -0,0 +1,25 @@ + + + + + + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + From 1b6ab9b1f4a0e74af637fa626919e9d5c029e8c3 Mon Sep 17 00:00:00 2001 From: Jim Ewald Date: Mon, 30 Jan 2017 14:56:39 -0800 Subject: [PATCH 4/7] Add logging to a few DAO-layer classes. Update Monitor class to split JVM logging from application events logging. --- .../server/blocklyprop/config/DaoModule.java | 17 +++ .../blocklyprop/config/PersistenceModule.java | 6 +- .../db/dao/impl/ProjectDaoImpl.java | 123 +++++++++++++++--- .../blocklyprop/monitoring/Monitor.java | 60 ++++++++- 4 files changed, 184 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/parallax/server/blocklyprop/config/DaoModule.java b/src/main/java/com/parallax/server/blocklyprop/config/DaoModule.java index 6d6bd6ad..bd1f3dde 100644 --- a/src/main/java/com/parallax/server/blocklyprop/config/DaoModule.java +++ b/src/main/java/com/parallax/server/blocklyprop/config/DaoModule.java @@ -15,9 +15,26 @@ import com.parallax.server.blocklyprop.db.dao.impl.SessionDaoImpl; import com.parallax.server.blocklyprop.db.dao.impl.UserDaoImpl; + /** * * @author Michel + * + * AbstractModule: + * A support class for Modules which reduces repetition and results in a more + * readable configuration. Simply extend this class, implement configure(), + * and call the inherited methods which mirror those found in Binder. + * For example: + * + * public class MyModule extends AbstractModule { + * protected void configure() { + * bind(Service.class).to(ServiceImpl.class).in(Singleton.class); + * bind(CreditCardPaymentService.class); + * bind(PaymentService.class).to(CreditCardPaymentService.class); + * bindConstant().annotatedWith(Names.named("port")).to(8080); + * } + * } + * */ public class DaoModule extends AbstractModule { diff --git a/src/main/java/com/parallax/server/blocklyprop/config/PersistenceModule.java b/src/main/java/com/parallax/server/blocklyprop/config/PersistenceModule.java index 5fae250d..5311fe62 100644 --- a/src/main/java/com/parallax/server/blocklyprop/config/PersistenceModule.java +++ b/src/main/java/com/parallax/server/blocklyprop/config/PersistenceModule.java @@ -10,12 +10,13 @@ import com.google.inject.Provides; import com.parallax.server.blocklyprop.db.utils.DataSourceSetup; import java.sql.SQLException; -import java.util.logging.Level; -import java.util.logging.Logger; import javax.sql.DataSource; import org.apache.commons.configuration.Configuration; import org.apache.commons.dbcp2.PoolingDataSource; import org.jooq.SQLDialect; +import java.util.logging.Level; +import java.util.logging.Logger; + /** * @@ -37,6 +38,7 @@ protected void configure() { @Provides PoolingDataSource dataSource() throws ClassNotFoundException { + PoolingDataSource ds = DataSourceSetup.connect(configuration); try { ds.getConnection(); diff --git a/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/ProjectDaoImpl.java b/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/ProjectDaoImpl.java index 3fb88f2c..80f9489d 100644 --- a/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/ProjectDaoImpl.java +++ b/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/ProjectDaoImpl.java @@ -39,8 +39,9 @@ public void setDSLContext(DSLContext dsl) { // Swap out old block definitions private ProjectRecord alterReadRecord(ProjectRecord record) { - LOG.info("Updating outdated block definitions"); - String newCode; + LOG.info("Verify project block characteristics"); + String currentCode, newCode; + if (record == null) { LOG.error("Null project record detected."); @@ -48,13 +49,21 @@ private ProjectRecord alterReadRecord(ProjectRecord record) { } try { - newCode = record.getCode(); + currentCode = record.getCode(); // Return immediately if there is no code to adjust - if (newCode == null) { + if (currentCode == null) { + LOG.warn("Project is empty."); return record; } + /* + * Make a copy of the project. We will use this after the updates + * to determine if anything was changed. This ensures that we do + * not do any database I/O unless we actually changed something. + */ + newCode = currentCode; + if (record.getType() == ProjectType.SPIN) { newCode = newCode.replaceAll("block type=\"controls_if\"", "block type=\"controls_boolean_if\""); newCode = newCode.replaceAll("block type=\"logic_compare\"", "block type=\"logic_boolean_compare\""); @@ -86,11 +95,14 @@ private ProjectRecord alterReadRecord(ProjectRecord record) { newCode = newCode.replaceAll("block type=\"logic_boolean_negate\"", "block type=\"logic_negate\""); } - record.setCode(newCode); + // Check for any difference from the original code + if (! currentCode.equals(newCode)) { + record.setCode(newCode); + } } catch (Exception ex) { - System.out.print(ex.getMessage()); + LOG.error("Exception trapped. Messate is: {}", ex.getMessage()); } return record; @@ -98,42 +110,119 @@ private ProjectRecord alterReadRecord(ProjectRecord record) { @Override public ProjectRecord getProject(Long idProject) { - ProjectRecord record = create.selectFrom(Tables.PROJECT).where(Tables.PROJECT.ID.equal(idProject)).fetchOne(); + LOG.info("Retreiving project: {}", idProject); + + ProjectRecord record = create + .selectFrom(Tables.PROJECT) + .where(Tables.PROJECT.ID.equal(idProject)) + .fetchOne(); + // Return the project after checking if for depricated blocks return alterReadRecord(record); } + private ProjectRecord getProject(Long idProject, boolean toEdit) { - ProjectRecord record = create.selectFrom(Tables.PROJECT).where(Tables.PROJECT.ID.equal(idProject)).fetchOne(); + + ProjectRecord record = create + .selectFrom(Tables.PROJECT) + .where(Tables.PROJECT.ID.equal(idProject)) + .fetchOne(); + if (record != null) { Long idUser = BlocklyPropSecurityUtils.getCurrentUserId(); + + // Return a project if the edit flag is off or the edit flag is + // on and the project owner is the current user if (!toEdit || record.getIdUser().equals(idUser)) { - return record; + return alterReadRecord(record); } else { + LOG.error("User {} attempted to edit project {} without authorization.", + idUser, idProject); throw new UnauthorizedException(); } - } + // Return the project after checking if for depricated blocks return alterReadRecord(record); } @Override - public ProjectRecord createProject(String name, String description, String descriptionHtml, String code, ProjectType type, String board, boolean privateProject, boolean sharedProject) { + public ProjectRecord createProject( + String name, String description, String descriptionHtml, + String code, ProjectType type, String board, boolean privateProject, + boolean sharedProject) { + + LOG.info("Creating a new project."); Long idUser = BlocklyPropSecurityUtils.getCurrentUserId(); Long idCloudUser = BlocklyPropSecurityUtils.getCurrentSessionUserId(); - ProjectRecord record = create.insertInto(Tables.PROJECT, Tables.PROJECT.ID_USER, Tables.PROJECT.ID_CLOUDUSER, Tables.PROJECT.NAME, Tables.PROJECT.DESCRIPTION, Tables.PROJECT.DESCRIPTION_HTML, Tables.PROJECT.CODE, Tables.PROJECT.TYPE, Tables.PROJECT.BOARD, Tables.PROJECT.PRIVATE, Tables.PROJECT.SHARED) - .values(idUser, idCloudUser, name, description, descriptionHtml, code, type, board, privateProject, sharedProject).returning().fetchOne(); + + ProjectRecord record = create + .insertInto(Tables.PROJECT, + Tables.PROJECT.ID_USER, + Tables.PROJECT.ID_CLOUDUSER, + Tables.PROJECT.NAME, + Tables.PROJECT.DESCRIPTION, + Tables.PROJECT.DESCRIPTION_HTML, + Tables.PROJECT.CODE, + Tables.PROJECT.TYPE, + Tables.PROJECT.BOARD, + Tables.PROJECT.PRIVATE, + Tables.PROJECT.SHARED) + .values(idUser, + idCloudUser, + name, + description, + descriptionHtml, + code, + type, + board, + privateProject, + sharedProject) + .returning() + .fetchOne(); return record; } - public ProjectRecord createProject(String name, String description, String descriptionHtml, String code, ProjectType type, String board, boolean privateProject, boolean sharedProject, Long idProjectBasedOn) { + // Overload to create project from an existing project + public ProjectRecord createProject( + String name, String description, String descriptionHtml, + String code, ProjectType type, String board, boolean privateProject, + boolean sharedProject, Long idProjectBasedOn) { + + LOG.info("Creating a new project from existing project."); Long idUser = BlocklyPropSecurityUtils.getCurrentUserId(); Long idCloudUser = BlocklyPropSecurityUtils.getCurrentSessionUserId(); - ProjectRecord record = create.insertInto(Tables.PROJECT, Tables.PROJECT.ID_USER, Tables.PROJECT.ID_CLOUDUSER, Tables.PROJECT.NAME, Tables.PROJECT.DESCRIPTION, Tables.PROJECT.DESCRIPTION_HTML, Tables.PROJECT.CODE, Tables.PROJECT.TYPE, Tables.PROJECT.BOARD, Tables.PROJECT.PRIVATE, Tables.PROJECT.SHARED, Tables.PROJECT.BASED_ON) - .values(idUser, idCloudUser, name, description, descriptionHtml, code, type, board, privateProject, sharedProject, idProjectBasedOn).returning().fetchOne(); - System.out.println("Save as: " + record.getName()); + + ProjectRecord record = create + .insertInto(Tables.PROJECT, + Tables.PROJECT.ID_USER, + Tables.PROJECT.ID_CLOUDUSER, + Tables.PROJECT.NAME, + Tables.PROJECT.DESCRIPTION, + Tables.PROJECT.DESCRIPTION_HTML, + Tables.PROJECT.CODE, + Tables.PROJECT.TYPE, + Tables.PROJECT.BOARD, + Tables.PROJECT.PRIVATE, + Tables.PROJECT.SHARED, + Tables.PROJECT.BASED_ON) + .values(idUser, + idCloudUser, + name, + description, + descriptionHtml, + code, + type, + board, + privateProject, + sharedProject, + idProjectBasedOn) + .returning() + .fetchOne(); + + LOG.info("New project saved as {}.", record.getName()); return record; } diff --git a/src/main/java/com/parallax/server/blocklyprop/monitoring/Monitor.java b/src/main/java/com/parallax/server/blocklyprop/monitoring/Monitor.java index c61ec60b..f7d69f8f 100644 --- a/src/main/java/com/parallax/server/blocklyprop/monitoring/Monitor.java +++ b/src/main/java/com/parallax/server/blocklyprop/monitoring/Monitor.java @@ -56,13 +56,66 @@ public Monitor(Configuration configuration) { graphiteServerPort = configuration.getInt("monitor.graphite.port", 2003); graphiteReportingInterval = configuration.getInt("monitor.graphite.interval", 30); - init(); + if (consoleEnabled) { + initConsoleReporter(); + } + + if (graphiteEnabled) { + initGraphiteReporter(); + } + + // initFileLogger(); + + // JVM memory utilization stats + MemoryUsageGaugeSet memoryUsageGaugeSet = new MemoryUsageGaugeSet(); + metrics.registerAll(memoryUsageGaugeSet); + + // JVM garbage collecion stats + GarbageCollectorMetricSet garbageCollectorMetricSet = new GarbageCollectorMetricSet(); + metrics.registerAll(garbageCollectorMetricSet); + + } + + private void initConsoleReporter() { + ConsoleReporter reporter = + ConsoleReporter + .forRegistry(metrics) + .convertDurationsTo(TimeUnit.MILLISECONDS) + .build(); + reporter.start(consoleReportingInterval, TimeUnit.SECONDS); + } + + private void initGraphiteReporter() { + final PickledGraphite pickledGraphite = new PickledGraphite( + new InetSocketAddress( + graphiteServerAddress, + graphiteServerPort)); + + final GraphiteReporter graphiteReporter = + GraphiteReporter + .forRegistry(metrics) + .prefixedWith(graphitePrefix) + .convertDurationsTo(TimeUnit.MILLISECONDS). + filter(MetricFilter.ALL).build(pickledGraphite); + + graphiteReporter.start(graphiteReportingInterval, TimeUnit.SECONDS); + } + + private void initFileLogger() { + final Slf4jReporter reporter = Slf4jReporter + .forRegistry(metrics) + .outputTo(LoggerFactory.getLogger(Monitor.class)) + .convertRatesTo(TimeUnit.SECONDS) + .convertDurationsTo(TimeUnit.MILLISECONDS) + .build(); + reporter.start(graphiteReportingInterval, TimeUnit.SECONDS); + } private void init() { // final LoggerContext factory = (LoggerContext) LoggerFactory.getILoggerFactory(); - +/* if (consoleEnabled) { ConsoleReporter reporter = ConsoleReporter @@ -92,7 +145,7 @@ private void init() { .convertRatesTo(TimeUnit.SECONDS) .convertDurationsTo(TimeUnit.MILLISECONDS) .build(); - reporter.start(5, TimeUnit.SECONDS); + reporter.start(graphiteReportingInterval, TimeUnit.SECONDS); // InstrumentedAppender appender = new InstrumentedAppender(metrics); // appender.setContext(context); @@ -106,6 +159,7 @@ private void init() { GarbageCollectorMetricSet garbageCollectorMetricSet = new GarbageCollectorMetricSet(); metrics.registerAll(garbageCollectorMetricSet); +*/ } public static MetricRegistry metrics() { From d5d7233325a8e90cef3a0a6067866dcbdf9761e8 Mon Sep 17 00:00:00 2001 From: Jim Ewald Date: Mon, 30 Jan 2017 15:48:29 -0800 Subject: [PATCH 5/7] Refactor block update code. Add javadoc comments to public methods. --- .../db/dao/impl/ProjectDaoImpl.java | 460 +++++++++++++----- 1 file changed, 341 insertions(+), 119 deletions(-) diff --git a/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/ProjectDaoImpl.java b/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/ProjectDaoImpl.java index 80f9489d..9390505c 100644 --- a/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/ProjectDaoImpl.java +++ b/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/ProjectDaoImpl.java @@ -26,6 +26,8 @@ /** * * @author Michel + * + * TODO: add details. */ @Singleton public class ProjectDaoImpl implements ProjectDao { @@ -37,77 +39,15 @@ public void setDSLContext(DSLContext dsl) { this.create = dsl; } - // Swap out old block definitions - private ProjectRecord alterReadRecord(ProjectRecord record) { - LOG.info("Verify project block characteristics"); - String currentCode, newCode; - - - if (record == null) { - LOG.error("Null project record detected."); - throw new NullPointerException("Cannot alter a null project record."); - } - - try { - currentCode = record.getCode(); - - // Return immediately if there is no code to adjust - if (currentCode == null) { - LOG.warn("Project is empty."); - return record; - } - - /* - * Make a copy of the project. We will use this after the updates - * to determine if anything was changed. This ensures that we do - * not do any database I/O unless we actually changed something. - */ - newCode = currentCode; - - if (record.getType() == ProjectType.SPIN) { - newCode = newCode.replaceAll("block type=\"controls_if\"", "block type=\"controls_boolean_if\""); - newCode = newCode.replaceAll("block type=\"logic_compare\"", "block type=\"logic_boolean_compare\""); - newCode = newCode.replaceAll("block type=\"logic_operation\"", "block type=\"logic_boolean_operation\""); - newCode = newCode.replaceAll("block type=\"logic_negate\"", "block type=\"logic_boolean_negate\""); - newCode = newCode.replaceAll("block type=\"math_number\"", "block type=\"spin_integer\""); - } else if (record.getType() == ProjectType.PROPC){ - newCode = newCode.replaceAll("field name=\"OP\">ADD + MINUS - MULTIPLY * DIVIDE / MODULUS % AND && AND_NOT && !LT<GT>LTE<=GTE>=EQ==NEQ!=INCHES_inchesCM_cm getUserProjects(Long idUser, TableSort sort, TableOrder order, Integer limit, Integer offset) { SortField orderField = Tables.PROJECT.NAME.asc(); @@ -298,6 +312,16 @@ public List getUserProjects(Long idUser, TableSort sort, TableOrd return create.selectFrom(Tables.PROJECT).where(Tables.PROJECT.ID_USER.equal(idUser)).orderBy(orderField).limit(limit).offset(offset).fetch(); } + /** + * TODO: add details. + * + * @param sort + * @param order + * @param limit + * @param offset + * @param idUser + * @return + */ @Override public List getSharedProjects(TableSort sort, TableOrder order, Integer limit, Integer offset, Long idUser) { SortField orderField = sort == null ? Tables.PROJECT.NAME.asc() : sort.getField().asc(); @@ -311,11 +335,24 @@ public List getSharedProjects(TableSort sort, TableOrder order, I return create.selectFrom(Tables.PROJECT).where(conditions).orderBy(orderField).limit(limit).offset(offset).fetch(); } + /** + * TODO: add details. + * + * @param idUser + * @return + */ @Override public int countUserProjects(Long idUser) { return create.fetchCount(Tables.PROJECT, Tables.PROJECT.ID_USER.equal(idUser)); } + /** + * + * TODO: add details. + * + * @param idUser + * @return + */ @Override public int countSharedProjects(Long idUser) { Condition conditions = Tables.PROJECT.SHARED.equal(Boolean.TRUE); @@ -325,6 +362,12 @@ public int countSharedProjects(Long idUser) { return create.fetchCount(Tables.PROJECT, conditions); } + /** + * TODO: add details. + * + * @param idProject + * @return + */ @Override public ProjectRecord cloneProject(Long idProject) { ProjectRecord original = getProject(idProject); @@ -338,26 +381,12 @@ public ProjectRecord cloneProject(Long idProject) { return null; } - private ProjectRecord doProjectClone(ProjectRecord original) { - ProjectRecord cloned = createProject( - original.getName(), - original.getDescription(), - original.getDescriptionHtml(), - original.getCode(), - original.getType(), - original.getBoard(), - original.getPrivate(), - original.getShared()); - - cloned.setBasedOn(original.getId()); - cloned.update(); - - create.update(Tables.PROJECT) - .set(Tables.PROJECT.BASED_ON, original.getId()) - .where(Tables.PROJECT.ID.equal(cloned.getId())); - return cloned; - } - + /** + * TODO: add details. + * + * @param idProject + * @return + */ @Override public boolean deleteProject(Long idProject) { return create.deleteFrom(Tables.PROJECT) @@ -365,6 +394,13 @@ public boolean deleteProject(Long idProject) { .execute() > 0; } + /** + * TODO: add details. + * + * @param idProject + * @param code + * @return + */ @Override public ProjectRecord updateProjectCode(Long idProject, String code) { ProjectRecord record = create.selectFrom(Tables.PROJECT) @@ -396,6 +432,14 @@ public ProjectRecord updateProjectCode(Long idProject, String code) { } } + /** + * TODO: add details. + * + * @param idProject + * @param code + * @param newName + * @return + */ @Override public ProjectRecord saveProjectCodeAs(Long idProject, String code, String newName) { ProjectRecord original = getProject(idProject); @@ -420,4 +464,182 @@ public ProjectRecord saveProjectCodeAs(Long idProject, String code, String newNa return null; } + + private ProjectRecord getProject(Long idProject, boolean toEdit) { + + ProjectRecord record = create + .selectFrom(Tables.PROJECT) + .where(Tables.PROJECT.ID.equal(idProject)) + .fetchOne(); + + if (record != null) { + Long idUser = BlocklyPropSecurityUtils.getCurrentUserId(); + + // Return a project if the edit flag is off or the edit flag is + // on and the project owner is the current user + if (!toEdit || record.getIdUser().equals(idUser)) { + return alterReadRecord(record); + } else { + LOG.error("User {} attempted to edit project {} without authorization.", + idUser, idProject); + throw new UnauthorizedException(); + } + } + + // Return the project after checking if for depricated blocks + return alterReadRecord(record); + } + + private ProjectRecord doProjectClone(ProjectRecord original) { + ProjectRecord cloned = createProject( + original.getName(), + original.getDescription(), + original.getDescriptionHtml(), + original.getCode(), + original.getType(), + original.getBoard(), + original.getPrivate(), + original.getShared()); + + cloned.setBasedOn(original.getId()); + cloned.update(); + + create.update(Tables.PROJECT) + .set(Tables.PROJECT.BASED_ON, original.getId()) + .where(Tables.PROJECT.ID.equal(cloned.getId())); + return cloned; + } + + + // Swap out old block definitions + private ProjectRecord alterReadRecord(ProjectRecord record) { + LOG.info("Verify project block characteristics"); + String currentCode, newCode; + + + if (record == null) { + LOG.error("Null project record detected."); + throw new NullPointerException("Cannot alter a null project record."); + } + + try { + currentCode = record.getCode(); + + // Return immediately if there is no code to adjust + if (currentCode == null) { + LOG.warn("Project is empty."); + return record; + } + + /* + * Make a copy of the project. We will use this after the updates + * to determine if anything was changed. This ensures that we do + * not do any database I/O unless we actually changed something. + */ + newCode = currentCode; + + if (record.getType() == ProjectType.SPIN) { + newCode = fixSpinProjectBlocks(newCode); + + } else if (record.getType() == ProjectType.PROPC){ + newCode = fixSpinProjectBlocks(newCode); + } + + // Check for any difference from the original code + if (! currentCode.equals(newCode)) { + LOG.info("Updating converted project."); + record.setCode(newCode); + } + } + + catch (Exception ex) { + LOG.error("Exception trapped. Messate is: {}", ex.getMessage()); + } + + return record; + } + + // Correct depricated block details related to Spin blocks + private String fixSpinProjectBlocks(String newCode) { + LOG.info("Looking for depricated Spin blocks."); + + newCode = newCode.replaceAll("block type=\"controls_if\"", + "block type=\"controls_boolean_if\""); + + newCode = newCode.replaceAll("block type=\"logic_compare\"", + "block type=\"logic_boolean_compare\""); + + newCode = newCode.replaceAll("block type=\"logic_operation\"", + "block type=\"logic_boolean_operation\""); + + newCode = newCode.replaceAll("block type=\"logic_negate\"", + "block type=\"logic_boolean_negate\""); + + newCode = newCode.replaceAll("block type=\"math_number\"", + "block type=\"spin_integer\""); + return newCode; + } + + private String fixPropcProjectBlocks(String newCode) { + LOG.info("Looking for depricated PropC blocks."); + + newCode = newCode.replaceAll("field name=\"OP\">ADD + MINUS - MULTIPLY * DIVIDE / MODULUS % AND && AND_NOT && !LT<GT>LTE<=GTE>=EQ==NEQ!=INCHES_inchesCM_cm Date: Mon, 30 Jan 2017 17:32:20 -0800 Subject: [PATCH 6/7] Add more logging calls. Updated logback configuration to paramerterize the log file location. --- .../db/dao/impl/ProjectDaoImpl.java | 74 ++++++++++++++----- src/main/resources/logback.xml | 5 +- 2 files changed, 61 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/ProjectDaoImpl.java b/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/ProjectDaoImpl.java index 9390505c..6fd99178 100644 --- a/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/ProjectDaoImpl.java +++ b/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/ProjectDaoImpl.java @@ -83,7 +83,7 @@ public ProjectRecord createProject( String code, ProjectType type, String board, boolean privateProject, boolean sharedProject) { - LOG.info("Creating a new project."); + LOG.info("Creating a new project with existing code."); Long idUser = BlocklyPropSecurityUtils.getCurrentUserId(); Long idCloudUser = BlocklyPropSecurityUtils.getCurrentSessionUserId(); @@ -218,22 +218,28 @@ public ProjectRecord updateProject( Long idProject, String name, String description, String descriptionHtml, boolean privateProject, boolean sharedProject) { - ProjectRecord record = getProject(idProject, true); - if (record != null) { - record.setName(name); - record.setDescription(description); - record.setDescriptionHtml(descriptionHtml); - record.setPrivate(privateProject); - record.setShared(sharedProject); - GregorianCalendar cal = new GregorianCalendar(); - cal.setTime(new java.util.Date()); + LOG.info("Update project {}.", idProject); - record.setModified(cal); - record.update(); - return record; + ProjectRecord record = getProject(idProject, true); + if (record == null) { + LOG.warn("Unable to locate project {} to update it.", idProject); + return null; } - return null; + + record.setName(name); + record.setDescription(description); + record.setDescriptionHtml(descriptionHtml); + record.setPrivate(privateProject); + record.setShared(sharedProject); + + GregorianCalendar cal = new GregorianCalendar(); + cal.setTime(new java.util.Date()); + + record.setModified(cal); + record.update(); + + return record; } /** @@ -256,6 +262,9 @@ public ProjectRecord updateProject( Long idProject, String name, String description, String descriptionHtml, String code, boolean privateProject, boolean sharedProject) { + + LOG.info("Update project {}.", idProject); + ProjectRecord record = getProject(idProject, true); if (record != null) { record.setName(name); @@ -270,8 +279,11 @@ public ProjectRecord updateProject( record.setModified(cal); record.update(); + return record; } + + LOG.warn("Unable to update project {}", idProject); return null; } @@ -284,12 +296,15 @@ public ProjectRecord updateProject( */ @Override public ProjectRecord saveCode(Long idProject, String code) { + LOG.info("Saving code for project {}.", idProject); + ProjectRecord record = getProject(idProject, true); if (record != null) { record.setCode(code); ProjectRecord returningRecord = create.update(Tables.PROJECT).set(record).returning().fetchOne(); return returningRecord; } + LOG.warn("Unable to save code for project {}", idProject); return null; } @@ -305,11 +320,17 @@ public ProjectRecord saveCode(Long idProject, String code) { */ @Override public List getUserProjects(Long idUser, TableSort sort, TableOrder order, Integer limit, Integer offset) { + LOG.info("Retreive projects for user {}.", idUser); + SortField orderField = Tables.PROJECT.NAME.asc(); if (TableOrder.desc == order) { orderField = Tables.PROJECT.NAME.desc(); } - return create.selectFrom(Tables.PROJECT).where(Tables.PROJECT.ID_USER.equal(idUser)).orderBy(orderField).limit(limit).offset(offset).fetch(); + + return create.selectFrom(Tables.PROJECT) + .where(Tables.PROJECT.ID_USER.equal(idUser)) + .orderBy(orderField).limit(limit).offset(offset) + .fetch(); } /** @@ -324,6 +345,8 @@ public List getUserProjects(Long idUser, TableSort sort, TableOrd */ @Override public List getSharedProjects(TableSort sort, TableOrder order, Integer limit, Integer offset, Long idUser) { + LOG.info("Retreive shared projects."); + SortField orderField = sort == null ? Tables.PROJECT.NAME.asc() : sort.getField().asc(); if (TableOrder.desc == order) { orderField = sort == null ? Tables.PROJECT.NAME.desc() : sort.getField().desc(); @@ -332,7 +355,10 @@ public List getSharedProjects(TableSort sort, TableOrder order, I if (idUser != null) { conditions = conditions.or(Tables.PROJECT.ID_USER.eq(idUser)); } - return create.selectFrom(Tables.PROJECT).where(conditions).orderBy(orderField).limit(limit).offset(offset).fetch(); + return create.selectFrom(Tables.PROJECT) + .where(conditions) + .orderBy(orderField).limit(limit).offset(offset) + .fetch(); } /** @@ -343,6 +369,8 @@ public List getSharedProjects(TableSort sort, TableOrder order, I */ @Override public int countUserProjects(Long idUser) { + LOG.info("Count project for user {}.", idUser); + return create.fetchCount(Tables.PROJECT, Tables.PROJECT.ID_USER.equal(idUser)); } @@ -355,6 +383,8 @@ public int countUserProjects(Long idUser) { */ @Override public int countSharedProjects(Long idUser) { + LOG.info("Count shared projects for user {}.", idUser); + Condition conditions = Tables.PROJECT.SHARED.equal(Boolean.TRUE); if (idUser != null) { conditions = conditions.or(Tables.PROJECT.ID_USER.eq(idUser)); @@ -370,6 +400,8 @@ public int countSharedProjects(Long idUser) { */ @Override public ProjectRecord cloneProject(Long idProject) { + LOG.info("Clone existing project {} to a new project.", idProject); + ProjectRecord original = getProject(idProject); if (original == null) { throw new NullPointerException("Project doesn't exist"); @@ -389,6 +421,7 @@ public ProjectRecord cloneProject(Long idProject) { */ @Override public boolean deleteProject(Long idProject) { + LOG.info("Delete project {}.", idProject); return create.deleteFrom(Tables.PROJECT) .where(Tables.PROJECT.ID.equal(idProject)) .execute() > 0; @@ -403,6 +436,7 @@ public boolean deleteProject(Long idProject) { */ @Override public ProjectRecord updateProjectCode(Long idProject, String code) { + LOG.info("Update code for project {}.", idProject); ProjectRecord record = create.selectFrom(Tables.PROJECT) .where(Tables.PROJECT.ID.equal(idProject)) .fetchOne(); @@ -425,9 +459,11 @@ public ProjectRecord updateProjectCode(Long idProject, String code) { cloned.update(); return cloned; } + LOG.error("User {} tried and failed to update project {}.", idUser, idProject); throw new UnauthorizedException(); } } else { + LOG.warn("Unable to project {}. Unknown reason.", idProject); return null; } } @@ -442,10 +478,14 @@ public ProjectRecord updateProjectCode(Long idProject, String code) { */ @Override public ProjectRecord saveProjectCodeAs(Long idProject, String code, String newName) { + LOG.info("Saving project code as '{}'", newName); + ProjectRecord original = getProject(idProject); if (original == null) { + LOG.error("Original project {} is missing. Unable to save code as...", idProject); throw new NullPointerException("Project doesn't exist"); } + Long idUser = BlocklyPropSecurityUtils.getCurrentUserId(); if (original.getIdUser().equals(idUser) || original.getShared()) { // TODO check if friends ProjectRecord cloned = createProject( @@ -466,7 +506,7 @@ public ProjectRecord saveProjectCodeAs(Long idProject, String code, String newNa private ProjectRecord getProject(Long idProject, boolean toEdit) { - + LOG.info("Retreiving project {}.", idProject); ProjectRecord record = create .selectFrom(Tables.PROJECT) .where(Tables.PROJECT.ID.equal(idProject)) diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml index ae2759e8..e4b551b2 100644 --- a/src/main/resources/logback.xml +++ b/src/main/resources/logback.xml @@ -9,6 +9,9 @@ and open the template in the editor. Valid logging levels: TRACE, DEBUG, INFO, WARN and ERROR --> + + + - +