diff --git a/src/main/app/js/directives.js b/src/main/app/js/directives.js index f77e56f0..200ebe83 100644 --- a/src/main/app/js/directives.js +++ b/src/main/app/js/directives.js @@ -360,3 +360,14 @@ module.directive('metricGauge', function() { templateUrl : 'templates/_metrics.gauge.html' }; }); + +module.directive('metricTimer', function() { + return { + scope : { + metric : '=', + label : '=' + }, + restrict : 'E', + templateUrl : 'templates/_metrics.timer.html' + }; +}); diff --git a/src/main/app/templates/_metrics.meter.html b/src/main/app/templates/_metrics.meter.html index dec86966..585d1386 100644 --- a/src/main/app/templates/_metrics.meter.html +++ b/src/main/app/templates/_metrics.meter.html @@ -4,14 +4,8 @@
Mean
{{metric.meanRate | number:2}}
-
1 min
-
{{metric.oneMinuteRate | number:2}}
- -
5 min
-
{{metric.fiveMinuteRate | number:2}}
- -
15 min
-
{{metric.fifteenMinuteRate | number:2}}
+
1/5/15 min
+
{{metric.oneMinuteRate | number:2}} {{metric.fiveMinuteRate | number:2}} {{metric.fifteenMinuteRate | number:2}}
Total
{{metric.count}}
diff --git a/src/main/app/templates/_metrics.timer.html b/src/main/app/templates/_metrics.timer.html new file mode 100644 index 00000000..638997f6 --- /dev/null +++ b/src/main/app/templates/_metrics.timer.html @@ -0,0 +1,17 @@ +
+ {{label}} +
+
Mean
+
{{metric.meanRate | number:2}}
+ +
1/5/15 min
+
{{metric.oneMinuteRate | number:2}} {{metric.fiveMinuteRate | number:2}} {{metric.fifteenMinuteRate | number:2}}
+ +
Total
+
{{metric.count}}
+ +
min/max/mean (ms)
+
{{metric.snapshot.min/1000000 | number:0}} {{metric.snapshot.max/1000000 | number:0}} {{metric.snapshot.mean/1000000 | number:0}}
+ +
+
\ No newline at end of file diff --git a/src/main/app/templates/admin.metrics.html b/src/main/app/templates/admin.metrics.html index 64f05657..d853fcbc 100644 --- a/src/main/app/templates/admin.metrics.html +++ b/src/main/app/templates/admin.metrics.html @@ -1,21 +1,28 @@
- - - - - +
+ + + + + + + + - - + + - - - - - - + + + +
+
+
+ +
+
\ No newline at end of file diff --git a/src/main/java/com/commafeed/frontend/resource/AdminREST.java b/src/main/java/com/commafeed/frontend/resource/AdminREST.java index 18bd77fa..e9f136ed 100644 --- a/src/main/java/com/commafeed/frontend/resource/AdminREST.java +++ b/src/main/java/com/commafeed/frontend/resource/AdminREST.java @@ -19,6 +19,7 @@ import javax.ws.rs.core.Response.Status; import org.apache.commons.lang3.StringUtils; import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.annotation.Timed; import com.commafeed.CommaFeedApplication; import com.commafeed.CommaFeedConfiguration; import com.commafeed.CommaFeedConfiguration.ApplicationSettings; @@ -42,10 +43,10 @@ import io.swagger.annotations.ApiParam; import lombok.RequiredArgsConstructor; @Path("/admin") -@Api(value = "/admin", description = "Operations about application administration") +@Api(value = "/admin") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) -@RequiredArgsConstructor(onConstructor = @__({ @Inject })) +@RequiredArgsConstructor(onConstructor = @__({ @Inject }) ) @Singleton public class AdminREST { @@ -60,6 +61,7 @@ public class AdminREST { @POST @UnitOfWork @ApiOperation(value = "Save or update a user", notes = "Save or update a user. If the id is not specified, a new user will be created") + @Timed public Response save(@SecurityCheck(Role.ADMIN) User user, @ApiParam(required = true) UserModel userModel) { Preconditions.checkNotNull(userModel); Preconditions.checkNotNull(userModel.getName()); @@ -114,6 +116,7 @@ public class AdminREST { @GET @UnitOfWork @ApiOperation(value = "Get user information", notes = "Get user information", response = UserModel.class) + @Timed public Response getUser(@SecurityCheck(Role.ADMIN) User user, @ApiParam(value = "user id", required = true) @PathParam("id") Long id) { Preconditions.checkNotNull(id); User u = userDAO.findById(id); @@ -130,6 +133,7 @@ public class AdminREST { @GET @UnitOfWork @ApiOperation(value = "Get all users", notes = "Get all users", response = UserModel.class, responseContainer = "List") + @Timed public Response getUsers(@SecurityCheck(Role.ADMIN) User user) { Map users = new HashMap<>(); for (UserRole role : userRoleDAO.findAll()) { @@ -157,6 +161,7 @@ public class AdminREST { @POST @UnitOfWork @ApiOperation(value = "Delete a user", notes = "Delete a user, and all his subscriptions") + @Timed public Response delete(@SecurityCheck(Role.ADMIN) User user, @ApiParam(required = true) IDRequest req) { Preconditions.checkNotNull(req); Preconditions.checkNotNull(req.getId()); @@ -176,6 +181,7 @@ public class AdminREST { @GET @UnitOfWork @ApiOperation(value = "Retrieve application settings", notes = "Retrieve application settings", response = ApplicationSettings.class) + @Timed public Response getSettings(@SecurityCheck(Role.ADMIN) User user) { return Response.ok(config.getApplicationSettings()).build(); } @@ -184,6 +190,7 @@ public class AdminREST { @GET @UnitOfWork @ApiOperation(value = "Retrieve server metrics") + @Timed public Response getMetrics(@SecurityCheck(Role.ADMIN) User user) { return Response.ok(metrics).build(); } diff --git a/src/main/java/com/commafeed/frontend/resource/CategoryREST.java b/src/main/java/com/commafeed/frontend/resource/CategoryREST.java index feff3410..67db7707 100644 --- a/src/main/java/com/commafeed/frontend/resource/CategoryREST.java +++ b/src/main/java/com/commafeed/frontend/resource/CategoryREST.java @@ -29,6 +29,7 @@ import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; +import com.codahale.metrics.annotation.Timed; import com.commafeed.CommaFeedConfiguration; import com.commafeed.backend.cache.CacheService; import com.commafeed.backend.dao.FeedCategoryDAO; @@ -69,11 +70,11 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @Path("/category") -@Api(value = "/category", description = "Operations about user categories") +@Api(value = "/category") @Slf4j @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) -@RequiredArgsConstructor(onConstructor = @__({ @Inject })) +@RequiredArgsConstructor(onConstructor = @__({ @Inject }) ) @Singleton public class CategoryREST { @@ -92,10 +93,13 @@ public class CategoryREST { @GET @UnitOfWork @ApiOperation(value = "Get category entries", notes = "Get a list of category entries", response = Entries.class) - public Response getCategoryEntries( - @SecurityCheck User user, + @Timed + public Response getCategoryEntries(@SecurityCheck User user, @ApiParam(value = "id of the category, 'all' or 'starred'", required = true) @QueryParam("id") String id, - @ApiParam(value = "all entries or only unread ones", allowableValues = "all,unread", required = true) @DefaultValue("unread") @QueryParam("readType") ReadingMode readType, + @ApiParam( + value = "all entries or only unread ones", + allowableValues = "all,unread", + required = true) @DefaultValue("unread") @QueryParam("readType") ReadingMode readType, @ApiParam(value = "only entries newer than this") @QueryParam("newerThan") Long newerThan, @ApiParam(value = "offset for paging") @DefaultValue("0") @QueryParam("offset") int offset, @ApiParam(value = "limit for paging, default 20, maximum 1000") @DefaultValue("20") @QueryParam("limit") int limit, @@ -103,7 +107,8 @@ public class CategoryREST { @ApiParam( value = "search for keywords in either the title or the content of the entries, separated by spaces, 3 characters minimum") @QueryParam("keywords") String keywords, @ApiParam(value = "return only entry ids") @DefaultValue("false") @QueryParam("onlyIds") boolean onlyIds, - @ApiParam(value = "comma-separated list of excluded subscription ids") @QueryParam("excludedSubscriptionIds") String excludedSubscriptionIds, + @ApiParam( + value = "comma-separated list of excluded subscription ids") @QueryParam("excludedSubscriptionIds") String excludedSubscriptionIds, @ApiParam(value = "keep only entries tagged with this tag") @QueryParam("tag") String tag) { Preconditions.checkNotNull(readType); @@ -138,18 +143,16 @@ public class CategoryREST { offset, limit + 1, order, true, onlyIds, tag); for (FeedEntryStatus status : list) { - entries.getEntries().add( - Entry.build(status, config.getApplicationSettings().getPublicUrl(), config.getApplicationSettings() - .getImageProxyEnabled())); + entries.getEntries().add(Entry.build(status, config.getApplicationSettings().getPublicUrl(), + config.getApplicationSettings().getImageProxyEnabled())); } } else if (STARRED.equals(id)) { entries.setName("Starred"); List starred = feedEntryStatusDAO.findStarred(user, newerThanDate, offset, limit + 1, order, !onlyIds); for (FeedEntryStatus status : starred) { - entries.getEntries().add( - Entry.build(status, config.getApplicationSettings().getPublicUrl(), config.getApplicationSettings() - .getImageProxyEnabled())); + entries.getEntries().add(Entry.build(status, config.getApplicationSettings().getPublicUrl(), + config.getApplicationSettings().getImageProxyEnabled())); } } else { FeedCategory parent = feedCategoryDAO.findById(user, Long.valueOf(id)); @@ -161,9 +164,8 @@ public class CategoryREST { offset, limit + 1, order, true, onlyIds, tag); for (FeedEntryStatus status : list) { - entries.getEntries().add( - Entry.build(status, config.getApplicationSettings().getPublicUrl(), config.getApplicationSettings() - .getImageProxyEnabled())); + entries.getEntries().add(Entry.build(status, config.getApplicationSettings().getPublicUrl(), + config.getApplicationSettings().getImageProxyEnabled())); } entries.setName(parent.getName()); } else { @@ -188,10 +190,13 @@ public class CategoryREST { @UnitOfWork @ApiOperation(value = "Get category entries as feed", notes = "Get a feed of category entries") @Produces(MediaType.APPLICATION_XML) - public Response getCategoryEntriesAsFeed( - @SecurityCheck(apiKeyAllowed = true) User user, + @Timed + public Response getCategoryEntriesAsFeed(@SecurityCheck(apiKeyAllowed = true) User user, @ApiParam(value = "id of the category, 'all' or 'starred'", required = true) @QueryParam("id") String id, - @ApiParam(value = "all entries or only unread ones", allowableValues = "all,unread", required = true) @DefaultValue("all") @QueryParam("readType") ReadingMode readType, + @ApiParam( + value = "all entries or only unread ones", + allowableValues = "all,unread", + required = true) @DefaultValue("all") @QueryParam("readType") ReadingMode readType, @ApiParam(value = "only entries newer than this") @QueryParam("newerThan") Long newerThan, @ApiParam(value = "offset for paging") @DefaultValue("0") @QueryParam("offset") int offset, @ApiParam(value = "limit for paging, default 20, maximum 1000") @DefaultValue("20") @QueryParam("limit") int limit, @@ -199,7 +204,8 @@ public class CategoryREST { @ApiParam( value = "search for keywords in either the title or the content of the entries, separated by spaces, 3 characters minimum") @QueryParam("keywords") String keywords, @ApiParam(value = "return only entry ids") @DefaultValue("false") @QueryParam("onlyIds") boolean onlyIds, - @ApiParam(value = "comma-separated list of excluded subscription ids") @QueryParam("excludedSubscriptionIds") String excludedSubscriptionIds, + @ApiParam( + value = "comma-separated list of excluded subscription ids") @QueryParam("excludedSubscriptionIds") String excludedSubscriptionIds, @ApiParam(value = "keep only entries tagged with this tag") @QueryParam("tag") String tag) { Response response = getCategoryEntries(user, id, readType, newerThan, offset, limit, order, keywords, onlyIds, @@ -231,6 +237,7 @@ public class CategoryREST { @POST @UnitOfWork @ApiOperation(value = "Mark category entries", notes = "Mark feed entries of this category as read") + @Timed public Response markCategoryEntries(@SecurityCheck User user, @ApiParam(value = "category id, or 'all'", required = true) MarkRequest req) { Preconditions.checkNotNull(req); @@ -272,6 +279,7 @@ public class CategoryREST { @POST @UnitOfWork @ApiOperation(value = "Add a category", notes = "Add a new feed category", response = Long.class) + @Timed public Response addCategory(@SecurityCheck User user, @ApiParam(required = true) AddCategoryRequest req) { Preconditions.checkNotNull(req); Preconditions.checkNotNull(req.getName()); @@ -295,6 +303,7 @@ public class CategoryREST { @Path("/delete") @UnitOfWork @ApiOperation(value = "Delete a category", notes = "Delete an existing feed category") + @Timed public Response deleteCategory(@SecurityCheck User user, @ApiParam(required = true) IDRequest req) { Preconditions.checkNotNull(req); @@ -327,6 +336,7 @@ public class CategoryREST { @Path("/modify") @UnitOfWork @ApiOperation(value = "Rename a category", notes = "Rename an existing feed category") + @Timed public Response modifyCategory(@SecurityCheck User user, @ApiParam(required = true) CategoryModificationRequest req) { Preconditions.checkNotNull(req); Preconditions.checkNotNull(req.getId()); @@ -381,6 +391,7 @@ public class CategoryREST { @Path("/collapse") @UnitOfWork @ApiOperation(value = "Collapse a category", notes = "Save collapsed or expanded status for a category") + @Timed public Response collapse(@SecurityCheck User user, @ApiParam(required = true) CollapseRequest req) { Preconditions.checkNotNull(req); Preconditions.checkNotNull(req.getId()); @@ -399,6 +410,7 @@ public class CategoryREST { @Path("/unreadCount") @UnitOfWork @ApiOperation(value = "Get unread count for feed subscriptions", response = UnreadCount.class, responseContainer = "List") + @Timed public Response getUnreadCount(@SecurityCheck User user) { Map unreadCount = feedSubscriptionService.getUnreadCount(user); return Response.ok(Lists.newArrayList(unreadCount.values())).build(); @@ -408,6 +420,7 @@ public class CategoryREST { @Path("/get") @UnitOfWork @ApiOperation(value = "Get feed categories", notes = "Get all categories and subscriptions of the user", response = Category.class) + @Timed public Response getSubscriptions(@SecurityCheck User user) { Category root = cache.getUserRootCategory(user); if (root == null) { diff --git a/src/main/java/com/commafeed/frontend/resource/EntryREST.java b/src/main/java/com/commafeed/frontend/resource/EntryREST.java index ecfce36d..57591f4e 100644 --- a/src/main/java/com/commafeed/frontend/resource/EntryREST.java +++ b/src/main/java/com/commafeed/frontend/resource/EntryREST.java @@ -12,6 +12,7 @@ import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; +import com.codahale.metrics.annotation.Timed; import com.commafeed.backend.dao.FeedEntryTagDAO; import com.commafeed.backend.model.User; import com.commafeed.backend.service.FeedEntryService; @@ -30,10 +31,10 @@ import io.swagger.annotations.ApiParam; import lombok.RequiredArgsConstructor; @Path("/entry") -@Api(value = "/entry", description = "Operations about feed entries") +@Api(value = "/entry") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) -@RequiredArgsConstructor(onConstructor = @__({ @Inject })) +@RequiredArgsConstructor(onConstructor = @__({ @Inject }) ) @Singleton public class EntryREST { @@ -45,6 +46,7 @@ public class EntryREST { @POST @UnitOfWork @ApiOperation(value = "Mark a feed entry", notes = "Mark a feed entry as read/unread") + @Timed public Response markFeedEntry(@SecurityCheck User user, @ApiParam(value = "Mark Request", required = true) MarkRequest req) { Preconditions.checkNotNull(req); Preconditions.checkNotNull(req.getId()); @@ -57,6 +59,7 @@ public class EntryREST { @POST @UnitOfWork @ApiOperation(value = "Mark multiple feed entries", notes = "Mark feed entries as read/unread") + @Timed public Response markFeedEntries(@SecurityCheck User user, @ApiParam(value = "Multiple Mark Request", required = true) MultipleMarkRequest req) { Preconditions.checkNotNull(req); @@ -73,6 +76,7 @@ public class EntryREST { @POST @UnitOfWork @ApiOperation(value = "Mark a feed entry", notes = "Mark a feed entry as read/unread") + @Timed public Response starFeedEntry(@SecurityCheck User user, @ApiParam(value = "Star Request", required = true) StarRequest req) { Preconditions.checkNotNull(req); Preconditions.checkNotNull(req.getId()); @@ -87,6 +91,7 @@ public class EntryREST { @GET @UnitOfWork @ApiOperation(value = "Get list of tags for the user", notes = "Get list of tags for the user") + @Timed public Response getTags(@SecurityCheck User user) { List tags = feedEntryTagDAO.findByUser(user); return Response.ok(tags).build(); @@ -96,6 +101,7 @@ public class EntryREST { @POST @UnitOfWork @ApiOperation(value = "Mark a feed entry", notes = "Mark a feed entry as read/unread") + @Timed public Response tagFeedEntry(@SecurityCheck User user, @ApiParam(value = "Tag Request", required = true) TagRequest req) { Preconditions.checkNotNull(req); Preconditions.checkNotNull(req.getEntryId()); diff --git a/src/main/java/com/commafeed/frontend/resource/FeedREST.java b/src/main/java/com/commafeed/frontend/resource/FeedREST.java index 85225e13..58e25581 100644 --- a/src/main/java/com/commafeed/frontend/resource/FeedREST.java +++ b/src/main/java/com/commafeed/frontend/resource/FeedREST.java @@ -35,6 +35,7 @@ import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.glassfish.jersey.media.multipart.FormDataParam; +import com.codahale.metrics.annotation.Timed; import com.commafeed.CommaFeedApplication; import com.commafeed.CommaFeedConfiguration; import com.commafeed.backend.cache.CacheService; @@ -90,11 +91,11 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @Path("/feed") -@Api(value = "/feed", description = "Operations about feeds") +@Api(value = "/feed") @Slf4j @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) -@RequiredArgsConstructor(onConstructor = @__({ @Inject })) +@RequiredArgsConstructor(onConstructor = @__({ @Inject }) ) @Singleton public class FeedREST { @@ -130,10 +131,13 @@ public class FeedREST { @GET @UnitOfWork @ApiOperation(value = "Get feed entries", notes = "Get a list of feed entries", response = Entries.class) - public Response getFeedEntries( - @SecurityCheck User user, + @Timed + public Response getFeedEntries(@SecurityCheck User user, @ApiParam(value = "id of the feed", required = true) @QueryParam("id") String id, - @ApiParam(value = "all entries or only unread ones", allowableValues = "all,unread", required = true) @DefaultValue("unread") @QueryParam("readType") ReadingMode readType, + @ApiParam( + value = "all entries or only unread ones", + allowableValues = "all,unread", + required = true) @DefaultValue("unread") @QueryParam("readType") ReadingMode readType, @ApiParam(value = "only entries newer than this") @QueryParam("newerThan") Long newerThan, @ApiParam(value = "offset for paging") @DefaultValue("0") @QueryParam("offset") int offset, @ApiParam(value = "limit for paging, default 20, maximum 1000") @DefaultValue("20") @QueryParam("limit") int limit, @@ -171,9 +175,8 @@ public class FeedREST { entryKeywords, newerThanDate, offset, limit + 1, order, true, onlyIds, null); for (FeedEntryStatus status : list) { - entries.getEntries().add( - Entry.build(status, config.getApplicationSettings().getPublicUrl(), config.getApplicationSettings() - .getImageProxyEnabled())); + entries.getEntries().add(Entry.build(status, config.getApplicationSettings().getPublicUrl(), + config.getApplicationSettings().getImageProxyEnabled())); } boolean hasMore = entries.getEntries().size() > limit; @@ -196,10 +199,13 @@ public class FeedREST { @UnitOfWork @ApiOperation(value = "Get feed entries as a feed", notes = "Get a feed of feed entries") @Produces(MediaType.APPLICATION_XML) - public Response getFeedEntriesAsFeed( - @SecurityCheck(apiKeyAllowed = true) User user, + @Timed + public Response getFeedEntriesAsFeed(@SecurityCheck(apiKeyAllowed = true) User user, @ApiParam(value = "id of the feed", required = true) @QueryParam("id") String id, - @ApiParam(value = "all entries or only unread ones", allowableValues = "all,unread", required = true) @DefaultValue("all") @QueryParam("readType") ReadingMode readType, + @ApiParam( + value = "all entries or only unread ones", + allowableValues = "all,unread", + required = true) @DefaultValue("all") @QueryParam("readType") ReadingMode readType, @ApiParam(value = "only entries newer than this") @QueryParam("newerThan") Long newerThan, @ApiParam(value = "offset for paging") @DefaultValue("0") @QueryParam("offset") int offset, @ApiParam(value = "limit for paging, default 20, maximum 1000") @DefaultValue("20") @QueryParam("limit") int limit, @@ -253,6 +259,7 @@ public class FeedREST { @Path("/fetch") @UnitOfWork @ApiOperation(value = "Fetch a feed", notes = "Fetch a feed by its url", response = FeedInfo.class) + @Timed public Response fetchFeed(@SecurityCheck User user, @ApiParam(value = "feed url", required = true) FeedInfoRequest req) { Preconditions.checkNotNull(req); Preconditions.checkNotNull(req.getUrl()); @@ -271,6 +278,7 @@ public class FeedREST { @GET @UnitOfWork @ApiOperation(value = "Queue all feeds of the user for refresh", notes = "Manually add all feeds of the user to the refresh queue") + @Timed public Response queueAllForRefresh(@SecurityCheck User user) { feedSubscriptionService.refreshAll(user); return Response.ok().build(); @@ -280,6 +288,7 @@ public class FeedREST { @POST @UnitOfWork @ApiOperation(value = "Queue a feed for refresh", notes = "Manually add a feed to the refresh queue") + @Timed public Response queueForRefresh(@SecurityCheck User user, @ApiParam(value = "Feed id") IDRequest req) { Preconditions.checkNotNull(req); @@ -298,6 +307,7 @@ public class FeedREST { @POST @UnitOfWork @ApiOperation(value = "Mark feed entries", notes = "Mark feed entries as read (unread is not supported)") + @Timed public Response markFeedEntries(@SecurityCheck User user, @ApiParam(value = "Mark request") MarkRequest req) { Preconditions.checkNotNull(req); Preconditions.checkNotNull(req.getId()); @@ -317,6 +327,7 @@ public class FeedREST { @Path("/get/{id}") @UnitOfWork @ApiOperation(value = "", notes = "") + @Timed public Response get(@SecurityCheck User user, @ApiParam(value = "user id", required = true) @PathParam("id") Long id) { Preconditions.checkNotNull(id); @@ -332,6 +343,7 @@ public class FeedREST { @Path("/favicon/{id}") @UnitOfWork @ApiOperation(value = "Fetch a feed's icon", notes = "Fetch a feed's icon") + @Timed public Response getFavicon(@SecurityCheck User user, @ApiParam(value = "subscription id") @PathParam("id") Long id) { Preconditions.checkNotNull(id); @@ -361,6 +373,7 @@ public class FeedREST { @Path("/subscribe") @UnitOfWork @ApiOperation(value = "Subscribe to a feed", notes = "Subscribe to a feed") + @Timed public Response subscribe(@SecurityCheck User user, @ApiParam(value = "subscription request", required = true) SubscribeRequest req) { Preconditions.checkNotNull(req); Preconditions.checkNotNull(req.getTitle()); @@ -387,6 +400,7 @@ public class FeedREST { @Path("/subscribe") @UnitOfWork @ApiOperation(value = "Subscribe to a feed", notes = "Subscribe to a feed") + @Timed public Response subscribe(@SecurityCheck User user, @ApiParam(value = "feed url", required = true) @QueryParam("url") String url) { try { @@ -414,6 +428,7 @@ public class FeedREST { @Path("/unsubscribe") @UnitOfWork @ApiOperation(value = "Unsubscribe from a feed", notes = "Unsubscribe from a feed") + @Timed public Response unsubscribe(@SecurityCheck User user, @ApiParam(required = true) IDRequest req) { Preconditions.checkNotNull(req); Preconditions.checkNotNull(req.getId()); @@ -430,6 +445,7 @@ public class FeedREST { @Path("/modify") @UnitOfWork @ApiOperation(value = "Modify a subscription", notes = "Modify a feed subscription") + @Timed public Response modify(@SecurityCheck User user, @ApiParam(value = "subscription id", required = true) FeedModificationRequest req) { Preconditions.checkNotNull(req); Preconditions.checkNotNull(req.getId()); @@ -489,12 +505,13 @@ public class FeedREST { @UnitOfWork @Consumes(MediaType.MULTIPART_FORM_DATA) @ApiOperation(value = "OPML import", notes = "Import an OPML file, posted as a FORM with the 'file' name") + @Timed public Response importOpml(@SecurityCheck User user, @FormDataParam("file") InputStream input) { String publicUrl = config.getApplicationSettings().getPublicUrl(); if (StringUtils.isBlank(publicUrl)) { - throw new WebApplicationException(Response.status(Status.INTERNAL_SERVER_ERROR) - .entity("Set the public URL in the admin section.").build()); + throw new WebApplicationException( + Response.status(Status.INTERNAL_SERVER_ERROR).entity("Set the public URL in the admin section.").build()); } if (CommaFeedApplication.USERNAME_DEMO.equals(user.getName())) { @@ -515,6 +532,7 @@ public class FeedREST { @UnitOfWork @Produces(MediaType.APPLICATION_XML) @ApiOperation(value = "OPML export", notes = "Export an OPML file of the user's subscriptions") + @Timed public Response exportOpml(@SecurityCheck User user) { Opml opml = opmlExporter.export(user); WireFeedOutput output = new WireFeedOutput(); diff --git a/src/main/java/com/commafeed/frontend/resource/PubSubHubbubCallbackREST.java b/src/main/java/com/commafeed/frontend/resource/PubSubHubbubCallbackREST.java index 2163e555..f90e0aa2 100644 --- a/src/main/java/com/commafeed/frontend/resource/PubSubHubbubCallbackREST.java +++ b/src/main/java/com/commafeed/frontend/resource/PubSubHubbubCallbackREST.java @@ -22,6 +22,7 @@ import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.annotation.Timed; import com.commafeed.CommaFeedConfiguration; import com.commafeed.backend.dao.FeedDAO; import com.commafeed.backend.feed.FeedParser; @@ -36,7 +37,7 @@ import lombok.extern.slf4j.Slf4j; @Path("/push") @Slf4j -@RequiredArgsConstructor(onConstructor = @__({ @Inject })) +@RequiredArgsConstructor(onConstructor = @__({ @Inject }) ) @Singleton public class PubSubHubbubCallbackREST { @@ -53,6 +54,7 @@ public class PubSubHubbubCallbackREST { @GET @UnitOfWork @Produces(MediaType.TEXT_PLAIN) + @Timed public Response verify(@QueryParam("hub.mode") String mode, @QueryParam("hub.topic") String topic, @QueryParam("hub.challenge") String challenge, @QueryParam("hub.lease_seconds") String leaseSeconds, @QueryParam("hub.verify_token") String verifyToken) { @@ -84,6 +86,7 @@ public class PubSubHubbubCallbackREST { @POST @UnitOfWork @Consumes({ MediaType.APPLICATION_ATOM_XML, "application/rss+xml" }) + @Timed public Response callback() { if (!config.getApplicationSettings().getPubsubhubbub()) { diff --git a/src/main/java/com/commafeed/frontend/resource/ServerREST.java b/src/main/java/com/commafeed/frontend/resource/ServerREST.java index 80cdf6ff..eeebc160 100644 --- a/src/main/java/com/commafeed/frontend/resource/ServerREST.java +++ b/src/main/java/com/commafeed/frontend/resource/ServerREST.java @@ -13,6 +13,7 @@ import javax.ws.rs.core.Response.Status; import org.apache.commons.lang3.StringUtils; +import com.codahale.metrics.annotation.Timed; import com.commafeed.CommaFeedConfiguration; import com.commafeed.backend.HttpGetter; import com.commafeed.backend.HttpGetter.HttpResult; @@ -27,10 +28,10 @@ import io.swagger.annotations.ApiOperation; import lombok.RequiredArgsConstructor; @Path("/server") -@Api(value = "/server", description = "Operations about server infos") +@Api(value = "/server") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) -@RequiredArgsConstructor(onConstructor = @__({ @Inject })) +@RequiredArgsConstructor(onConstructor = @__({ @Inject }) ) @Singleton public class ServerREST { @@ -41,6 +42,7 @@ public class ServerREST { @GET @UnitOfWork @ApiOperation(value = "Get server infos", notes = "Get server infos", response = ServerInfo.class) + @Timed public Response get() { ServerInfo infos = new ServerInfo(); infos.setAnnouncement(config.getApplicationSettings().getAnnouncement()); @@ -57,6 +59,7 @@ public class ServerREST { @UnitOfWork @ApiOperation(value = "proxy image") @Produces("image/png") + @Timed public Response get(@SecurityCheck User user, @QueryParam("u") String url) { if (!config.getApplicationSettings().getImageProxyEnabled()) { return Response.status(Status.FORBIDDEN).build(); diff --git a/src/main/java/com/commafeed/frontend/resource/UserREST.java b/src/main/java/com/commafeed/frontend/resource/UserREST.java index 4956b1c2..85a62d97 100644 --- a/src/main/java/com/commafeed/frontend/resource/UserREST.java +++ b/src/main/java/com/commafeed/frontend/resource/UserREST.java @@ -25,6 +25,7 @@ import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.time.DateUtils; import org.apache.http.client.utils.URIBuilder; +import com.codahale.metrics.annotation.Timed; import com.commafeed.CommaFeedApplication; import com.commafeed.CommaFeedConfiguration; import com.commafeed.backend.dao.UserDAO; @@ -61,11 +62,11 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @Path("/user") -@Api(value = "/user", description = "Operations about the user") +@Api(value = "/user") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) @Slf4j -@RequiredArgsConstructor(onConstructor = @__({ @Inject })) +@RequiredArgsConstructor(onConstructor = @__({ @Inject }) ) @Singleton public class UserREST { @@ -81,6 +82,7 @@ public class UserREST { @GET @UnitOfWork @ApiOperation(value = "Retrieve user settings", notes = "Retrieve user settings", response = Settings.class) + @Timed public Response getSettings(@SecurityCheck User user) { Settings s = new Settings(); UserSettings settings = userSettingsDAO.findByUser(user); @@ -135,6 +137,7 @@ public class UserREST { @POST @UnitOfWork @ApiOperation(value = "Save user settings", notes = "Save user settings") + @Timed public Response saveSettings(@SecurityCheck User user, @ApiParam(required = true) Settings settings) { Preconditions.checkNotNull(settings); @@ -173,6 +176,7 @@ public class UserREST { @GET @UnitOfWork @ApiOperation(value = "Retrieve user's profile", response = UserModel.class) + @Timed public Response get(@SecurityCheck User user) { UserModel userModel = new UserModel(); userModel.setId(user.getId()); @@ -192,6 +196,7 @@ public class UserREST { @POST @UnitOfWork @ApiOperation(value = "Save user's profile") + @Timed public Response save(@SecurityCheck User user, @ApiParam(required = true) ProfileModificationRequest request) { Preconditions.checkArgument(StringUtils.isBlank(request.getPassword()) || request.getPassword().length() >= 6); if (StringUtils.isNotBlank(request.getEmail())) { @@ -220,6 +225,7 @@ public class UserREST { @POST @UnitOfWork @ApiOperation(value = "Register a new account") + @Timed public Response register(@Valid @ApiParam(required = true) RegistrationRequest req, @Context SessionHelper sessionHelper) { try { User registeredUser = userService.register(req.getName(), req.getPassword(), req.getEmail(), Arrays.asList(Role.USER)); @@ -236,6 +242,7 @@ public class UserREST { @POST @UnitOfWork @ApiOperation(value = "Login and create a session") + @Timed public Response login(@ApiParam(required = true) LoginRequest req, @Context SessionHelper sessionHelper) { Optional user = userService.login(req.getName(), req.getPassword()); if (user.isPresent()) { @@ -250,6 +257,7 @@ public class UserREST { @POST @UnitOfWork @ApiOperation(value = "send a password reset email") + @Timed public Response sendPasswordReset(@Valid PasswordResetRequest req) { User user = userDAO.findByEmail(req.getEmail()); if (user == null) { @@ -271,9 +279,9 @@ public class UserREST { private String buildEmailContent(User user) throws Exception { String publicUrl = FeedUtils.removeTrailingSlash(config.getApplicationSettings().getPublicUrl()); publicUrl += "/rest/user/passwordResetCallback"; - return String - .format("You asked for password recovery for account '%s', follow this link to change your password. Ignore this if you didn't request a password recovery.", - user.getName(), callbackUrl(user, publicUrl)); + return String.format( + "You asked for password recovery for account '%s', follow this link to change your password. Ignore this if you didn't request a password recovery.", + user.getName(), callbackUrl(user, publicUrl)); } private String callbackUrl(User user, String publicUrl) throws Exception { @@ -285,6 +293,7 @@ public class UserREST { @GET @UnitOfWork @Produces(MediaType.TEXT_HTML) + @Timed public Response passwordRecoveryCallback(@QueryParam("email") String email, @QueryParam("token") String token) { Preconditions.checkNotNull(email); Preconditions.checkNotNull(token); @@ -320,6 +329,7 @@ public class UserREST { @POST @UnitOfWork @ApiOperation(value = "Delete the user account") + @Timed public Response delete(@SecurityCheck User user) { if (CommaFeedApplication.USERNAME_ADMIN.equals(user.getName()) || CommaFeedApplication.USERNAME_DEMO.equals(user.getName())) { return Response.status(Status.FORBIDDEN).build();