additional timer metrics

This commit is contained in:
Athou
2015-08-14 12:58:55 +02:00
parent 21710f55f3
commit 6647e4fcd4
11 changed files with 158 additions and 69 deletions

View File

@@ -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'
};
});

View File

@@ -4,14 +4,8 @@
<dt>Mean</dt>
<dd>{{metric.meanRate | number:2}}</dd>
<dt>1 min</dt>
<dd>{{metric.oneMinuteRate | number:2}}</dd>
<dt>5 min</dt>
<dd>{{metric.fiveMinuteRate | number:2}}</dd>
<dt>15 min</dt>
<dd>{{metric.fifteenMinuteRate | number:2}}</dd>
<dt>1/5/15 min</dt>
<dd>{{metric.oneMinuteRate | number:2}} {{metric.fiveMinuteRate | number:2}} {{metric.fifteenMinuteRate | number:2}}</dd>
<dt>Total</dt>
<dd>{{metric.count}}</dd>

View File

@@ -0,0 +1,17 @@
<div>
<span>{{label}}</span>
<dl class="dl-horizontal">
<dt>Mean</dt>
<dd>{{metric.meanRate | number:2}}</dd>
<dt>1/5/15 min</dt>
<dd>{{metric.oneMinuteRate | number:2}} {{metric.fiveMinuteRate | number:2}} {{metric.fifteenMinuteRate | number:2}}</dd>
<dt>Total</dt>
<dd>{{metric.count}}</dd>
<dt>min/max/mean (ms)</dt>
<dd>{{metric.snapshot.min/1000000 | number:0}} {{metric.snapshot.max/1000000 | number:0}} {{metric.snapshot.mean/1000000 | number:0}}</dd>
</dl>
</div>

View File

@@ -1,21 +1,28 @@
<div>
<metric-meter metric="metrics.meters['com.commafeed.backend.feed.FeedQueues.refill']" label="'Refresh queue refill rate (/sec)'"></metric-meter>
<metric-meter metric="metrics.meters['com.commafeed.backend.feed.FeedRefreshTaskGiver.feedRefreshed']" label="'Feed refreshed (/sec)'"></metric-meter>
<metric-meter metric="metrics.meters['com.commafeed.backend.feed.FeedRefreshUpdater.feedUpdated']" label="'Feed updated (/sec)'"></metric-meter>
<metric-meter metric="metrics.meters['com.commafeed.backend.feed.FeedRefreshUpdater.entryCacheHit']" label="'Entry cache hit (/sec)'"></metric-meter>
<metric-meter metric="metrics.meters['com.commafeed.backend.feed.FeedRefreshUpdater.entryCacheMiss']" label="'Entry cache miss (/sec)'"></metric-meter>
<div class="col-md-6">
<metric-meter metric="metrics.meters['com.commafeed.backend.feed.FeedQueues.refill']" label="'Refresh queue refill rate (/sec)'"></metric-meter>
<metric-meter metric="metrics.meters['com.commafeed.backend.feed.FeedRefreshTaskGiver.feedRefreshed']" label="'Feed refreshed (/sec)'"></metric-meter>
<metric-meter metric="metrics.meters['com.commafeed.backend.feed.FeedRefreshUpdater.feedUpdated']" label="'Feed updated (/sec)'"></metric-meter>
<metric-meter metric="metrics.meters['com.commafeed.backend.feed.FeedRefreshUpdater.entryCacheHit']" label="'Entry cache hit (/sec)'"></metric-meter>
<metric-meter metric="metrics.meters['com.commafeed.backend.feed.FeedRefreshUpdater.entryCacheMiss']" label="'Entry cache miss (/sec)'"></metric-meter>
<metric-gauge metric="metrics.gauges['com.commafeed.backend.feed.FeedRefreshExecutor.feed-refresh-updater.active']"
label="'Feed Updater active'"></metric-gauge>
<metric-gauge metric="metrics.gauges['com.commafeed.backend.feed.FeedRefreshExecutor.feed-refresh-updater.pending']"
label="'Feed Updater queued'"></metric-gauge>
<metric-gauge metric="metrics.gauges['com.commafeed.backend.feed.FeedRefreshExecutor.feed-refresh-updater.active']"
label="'Feed Updater active'"></metric-gauge>
<metric-gauge metric="metrics.gauges['com.commafeed.backend.feed.FeedRefreshExecutor.feed-refresh-updater.pending']"
label="'Feed Updater queued'"></metric-gauge>
<metric-gauge metric="metrics.gauges['com.commafeed.backend.feed.FeedRefreshExecutor.feed-refresh-worker.active']"
label="'Feed Worker active'"></metric-gauge>
<metric-gauge metric="metrics.gauges['com.commafeed.backend.feed.FeedRefreshExecutor.feed-refresh-worker.pending']"
label="'Feed Worker queued'"></metric-gauge>
<metric-gauge metric="metrics.gauges['com.commafeed.backend.feed.FeedRefreshExecutor.feed-refresh-worker.active']"
label="'Feed Worker active'"></metric-gauge>
<metric-gauge metric="metrics.gauges['com.commafeed.backend.feed.FeedRefreshExecutor.feed-refresh-worker.pending']"
label="'Feed Worker queued'"></metric-gauge>
<metric-gauge metric="metrics.gauges['com.commafeed.backend.feed.FeedQueues.addQueue']" label="'Task Giver Add Queue'"></metric-gauge>
<metric-gauge metric="metrics.gauges['com.commafeed.backend.feed.FeedQueues.takeQueue']" label="'Task Giver Take Queue'"></metric-gauge>
<metric-gauge metric="metrics.gauges['com.commafeed.backend.feed.FeedQueues.giveBackQueue']" label="'Task Giver Give Back Queue'"></metric-gauge>
<metric-gauge metric="metrics.gauges['com.commafeed.backend.feed.FeedQueues.addQueue']" label="'Task Giver Add Queue'"></metric-gauge>
<metric-gauge metric="metrics.gauges['com.commafeed.backend.feed.FeedQueues.takeQueue']" label="'Task Giver Take Queue'"></metric-gauge>
<metric-gauge metric="metrics.gauges['com.commafeed.backend.feed.FeedQueues.giveBackQueue']" label="'Task Giver Give Back Queue'"></metric-gauge>
</div>
<div class="col-md-6">
<div ng-repeat="(name, timer) in metrics.timers">
<metric-timer metric="timer" label="name"></metric-gauge>
</div>
</div>
</div>

View File

@@ -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<Long, UserModel> 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();
}

View File

@@ -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<FeedEntryStatus> 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<Long, UnreadCount> 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) {

View File

@@ -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<String> 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());

View File

@@ -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();

View File

@@ -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()) {

View File

@@ -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();

View File

@@ -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> 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', <a href='%s'>follow this link</a> 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', <a href='%s'>follow this link</a> 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();