diff --git a/pom.xml b/pom.xml index 540281e9cee73946d66f62e23ce08290b82ce125..947efbb02f791ceee8f27bfe0c99ce92db4a72ef 100644 --- a/pom.xml +++ b/pom.xml @@ -292,6 +292,11 @@ <artifactId>swagger-annotations</artifactId> <version>1.5.12</version> </dependency> + <dependency> + <groupId>com.codahale.metrics</groupId> + <artifactId>metrics-annotation</artifactId> + <version>3.0.2</version> + </dependency> </dependencies> <build> @@ -382,11 +387,6 @@ </execution> </executions> </plugin> - <plugin> - <groupId>org.codehaus.mojo</groupId> - <artifactId>aspectj-maven-plugin</artifactId> - <version>1.9</version> - </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-checkstyle-plugin</artifactId> diff --git a/src/main/java/de/thm/arsnova/services/UserService.java b/src/main/java/de/thm/arsnova/services/UserService.java index 51edbf0613094d74a7654813524f25550f3006ff..c3ced54d49e613afdc4e5f33250b4cd43655f83d 100644 --- a/src/main/java/de/thm/arsnova/services/UserService.java +++ b/src/main/java/de/thm/arsnova/services/UserService.java @@ -17,6 +17,7 @@ */ package de.thm.arsnova.services; +import com.codahale.metrics.annotation.Gauge; import com.github.leleuj.ss.oauth.client.authentication.OAuthAuthenticationToken; import de.thm.arsnova.dao.IDatabaseDao; import de.thm.arsnova.entities.DbUser; @@ -50,6 +51,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.util.UriUtils; +import org.stagemonitor.core.metrics.MonitorGauges; import javax.annotation.PreDestroy; import javax.mail.MessagingException; @@ -65,6 +67,7 @@ import java.util.regex.Pattern; * Performs all user related operations. */ @Service +@MonitorGauges public class UserService implements IUserService { private static final int LOGIN_TRY_RESET_DELAY_MS = 30 * 1000; @@ -325,6 +328,7 @@ public class UserService implements IUserService { } @Override + @Gauge public int loggedInUsers() { return user2session.size(); } diff --git a/src/main/java/de/thm/arsnova/socket/ARSnovaSocketIOServer.java b/src/main/java/de/thm/arsnova/socket/ARSnovaSocketIOServer.java index 75217e17bbf5c2381a4cd8f5102a04934163f82c..55401f938fc0b3424b925e828161a9dfe8b69d46 100644 --- a/src/main/java/de/thm/arsnova/socket/ARSnovaSocketIOServer.java +++ b/src/main/java/de/thm/arsnova/socket/ARSnovaSocketIOServer.java @@ -17,6 +17,8 @@ */ package de.thm.arsnova.socket; +import com.codahale.metrics.annotation.Metered; +import com.codahale.metrics.annotation.Timed; import com.corundumstudio.socketio.AckRequest; import com.corundumstudio.socketio.Configuration; import com.corundumstudio.socketio.SocketConfig; @@ -131,6 +133,7 @@ public class ARSnovaSocketIOServer implements ARSnovaSocket, NovaEventVisitor { server.addEventListener("setFeedback", Feedback.class, new DataListener<Feedback>() { @Override + @Timed(name = "setFeedbackEvent.onData") public void onData(final SocketIOClient client, final Feedback data, final AckRequest ackSender) { final User u = userService.getUser2SocketId(client.getSessionId()); if (u == null) { @@ -154,6 +157,7 @@ public class ARSnovaSocketIOServer implements ARSnovaSocket, NovaEventVisitor { server.addEventListener("setSession", Session.class, new DataListener<Session>() { @Override + @Timed(name = "setSessionEvent.onData") public void onData(final SocketIOClient client, final Session session, final AckRequest ackSender) { final User u = userService.getUser2SocketId(client.getSessionId()); if (null == u) { @@ -183,6 +187,7 @@ public class ARSnovaSocketIOServer implements ARSnovaSocket, NovaEventVisitor { de.thm.arsnova.entities.transport.InterposedQuestion.class, new DataListener<de.thm.arsnova.entities.transport.InterposedQuestion>() { @Override + @Timed(name = "readInterposedQuestionEvent.onData") public void onData( SocketIOClient client, de.thm.arsnova.entities.transport.InterposedQuestion question, @@ -213,6 +218,7 @@ public class ARSnovaSocketIOServer implements ARSnovaSocket, NovaEventVisitor { LearningProgressOptions.class, new DataListener<LearningProgressOptions>() { @Override + @Timed(name = "setLearningProgressOptionsEvent.onData") public void onData(SocketIOClient client, LearningProgressOptions progressOptions, AckRequest ack) { final User user = userService.getUser2SocketId(client.getSessionId()); final de.thm.arsnova.entities.Session session = sessionService.getSessionInternal(progressOptions.getSessionKeyword(), user); @@ -226,11 +232,13 @@ public class ARSnovaSocketIOServer implements ARSnovaSocket, NovaEventVisitor { server.addConnectListener(new ConnectListener() { @Override + @Timed public void onConnect(final SocketIOClient client) { } }); server.addDisconnectListener(new DisconnectListener() { @Override + @Timed public void onDisconnect(final SocketIOClient client) { if ( userService == null @@ -500,6 +508,7 @@ public class ARSnovaSocketIOServer implements ARSnovaSocket, NovaEventVisitor { @Async @Override + @Timed(name = "visit.NewAnswerEvent") public void visit(NewAnswerEvent event) { final String sessionKey = event.getSession().getKeyword(); this.reportAnswersToLecturerQuestionAvailable(event.getSession(), new Question(event.getQuestion())); @@ -518,6 +527,7 @@ public class ARSnovaSocketIOServer implements ARSnovaSocket, NovaEventVisitor { @Async @Override + @Timed(name = "visit.DeleteAnswerEvent") public void visit(DeleteAnswerEvent event) { final String sessionKey = event.getSession().getKeyword(); this.reportAnswersToLecturerQuestionAvailable(event.getSession(), new Question(event.getQuestion())); @@ -528,6 +538,7 @@ public class ARSnovaSocketIOServer implements ARSnovaSocket, NovaEventVisitor { @Async @Override + @Timed(name = "visit.PiRoundDelayedStartEvent") public void visit(PiRoundDelayedStartEvent event) { final String sessionKey = event.getSession().getKeyword(); broadcastInSession(sessionKey, "startDelayedPiRound", event.getPiRoundInformations()); @@ -535,6 +546,7 @@ public class ARSnovaSocketIOServer implements ARSnovaSocket, NovaEventVisitor { @Async @Override + @Timed(name = "visit.PiRoundEndEvent") public void visit(PiRoundEndEvent event) { final String sessionKey = event.getSession().getKeyword(); broadcastInSession(sessionKey, "endPiRound", event.getPiRoundEndInformations()); @@ -542,6 +554,7 @@ public class ARSnovaSocketIOServer implements ARSnovaSocket, NovaEventVisitor { @Async @Override + @Timed(name = "visit.PiRoundCancelEvent") public void visit(PiRoundCancelEvent event) { final String sessionKey = event.getSession().getKeyword(); broadcastInSession(sessionKey, "cancelPiRound", event.getQuestionId()); diff --git a/src/main/java/org/stagemonitor/core/metrics/MonitorGauges.java b/src/main/java/org/stagemonitor/core/metrics/MonitorGauges.java new file mode 100644 index 0000000000000000000000000000000000000000..8e0a25a74e0f899322288173063bca50ffbfadcb --- /dev/null +++ b/src/main/java/org/stagemonitor/core/metrics/MonitorGauges.java @@ -0,0 +1,25 @@ +package org.stagemonitor.core.metrics; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * When a type is marked with this annotation, the creation of gauges with + * @{@link com.codahale.metrics.annotation.Gauge} is activated for that type. + * + * <pre><code> + * \@MonitorGauges + * public class Queue { + * \@Gauge(name = "queueSize") + * public int getQueueSize() { + * return queue.size; + * } + * } + * </code></pre> + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface MonitorGauges { +} diff --git a/src/main/resources/log4j-dev.properties b/src/main/resources/log4j-dev.properties index cc7b1ff3bd255dd36091cfa89fc5377528d0059e..bae1f9dffd40cb8899c04e8280615aaf9ddf4a71 100644 --- a/src/main/resources/log4j-dev.properties +++ b/src/main/resources/log4j-dev.properties @@ -13,3 +13,5 @@ log4j.category.io.netty=INFO log4j.category.io.netty.channel.DefaultChannelPipeline=WARN log4j.category.net.sf.json=WARN log4j.category.org.springframework=INFO +log4j.category.org.stagemonitor.core=OFF +log4j.category.org.stagemonitor.requestmonitor=OFF diff --git a/src/main/resources/stagemonitor.properties b/src/main/resources/stagemonitor.properties new file mode 100644 index 0000000000000000000000000000000000000000..928b3aa225b7d5d27b06441b9ca3967354d9c32f --- /dev/null +++ b/src/main/resources/stagemonitor.properties @@ -0,0 +1,5 @@ +stagemonitor.active=true +stagemonitor.applicationName=ARSnova Backend +stagemonitor.instrument.include=de.thm.arsnova.controller,de.thm.arsnova.services,de.thm.arsnova.socket +stagemonitor.reporting.interval.console=180 +stagemonitor.web.monitorOnlyForwardedRequests=true diff --git a/src/main/webapp/WEB-INF/spring/arsnova-servlet.xml b/src/main/webapp/WEB-INF/spring/arsnova-servlet.xml index 5c9e2a49f688740b5c25869976345f991ff9a3d9..0d9097812adac4376298a23fcb609d8d576c8d6c 100644 --- a/src/main/webapp/WEB-INF/spring/arsnova-servlet.xml +++ b/src/main/webapp/WEB-INF/spring/arsnova-servlet.xml @@ -24,6 +24,8 @@ <bean class="de.thm.arsnova.web.ResponseInterceptorHandler" /> </mvc:interceptors> + <bean id="requestMappingHandlerMapping" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" primary="true"></bean> + <aop:aspectj-autoproxy /> <!-- Enables swgger ui-->