Add metrics for http/server/rest_api calls

Break these down by the view implementation class showing what part of
Gerrit handled the request.  Include latency information, aggregate
counts, and errors when HTTP status code is >= 400.

Change-Id: Ifc806e4dbf157b4eea368e9a223d8ad1e551b8e7
This commit is contained in:
Shawn Pearce
2015-11-12 15:02:40 -08:00
parent 232c18da1b
commit 81764c9c49
2 changed files with 96 additions and 2 deletions

View File

@@ -0,0 +1,78 @@
// Copyright (C) 2015 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gerrit.httpd.restapi;
import com.google.common.base.Strings;
import com.google.gerrit.httpd.restapi.RestApiServlet.ViewData;
import com.google.gerrit.metrics.Counter1;
import com.google.gerrit.metrics.Counter2;
import com.google.gerrit.metrics.Description;
import com.google.gerrit.metrics.Field;
import com.google.gerrit.metrics.MetricMaker;
import com.google.gerrit.metrics.Timer1;
import com.google.gerrit.metrics.Description.Units;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@Singleton
public class RestApiMetrics {
private static final String[] PKGS = {
"com.google.gerrit.server.",
"com.google.gerrit.",
};
final Counter1<String> count;
final Counter2<String, Integer> errorCount;
final Timer1<String> serverLatency;
@Inject
RestApiMetrics(MetricMaker metrics) {
Field<String> view = Field.ofString("view", "view implementation class");
count = metrics.newCounter(
"http/server/rest_api/count",
new Description("REST API calls by view")
.setRate(),
view);
errorCount = metrics.newCounter(
"http/server/rest_api/error_count",
new Description("REST API calls by view")
.setRate(),
view,
Field.ofInteger("error_code", "HTTP status code"));
serverLatency = metrics.newTimer(
"http/server/rest_api/server_latency",
new Description("REST API call latency by view")
.setCumulative()
.setUnit(Units.MILLISECONDS),
view);
}
String view(ViewData viewData) {
String impl = viewData.view.getClass().getName().replace('$', '.');
for (String p : PKGS) {
if (impl.startsWith(p)) {
impl = impl.substring(p.length());
break;
}
}
if (!Strings.isNullOrEmpty(viewData.pluginName)
&& !"gerrit".equals(viewData.pluginName)) {
impl = viewData.pluginName + '-' + impl;
}
return impl;
}
}

View File

@@ -125,6 +125,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
import java.util.zip.GZIPOutputStream;
@@ -164,16 +165,19 @@ public class RestApiServlet extends HttpServlet {
final DynamicItem<WebSession> webSession;
final Provider<ParameterParser> paramParser;
final AuditService auditService;
final RestApiMetrics metrics;
@Inject
Globals(Provider<CurrentUser> currentUser,
DynamicItem<WebSession> webSession,
Provider<ParameterParser> paramParser,
AuditService auditService) {
AuditService auditService,
RestApiMetrics metrics) {
this.currentUser = currentUser;
this.webSession = webSession;
this.paramParser = paramParser;
this.auditService = auditService;
this.metrics = metrics;
}
}
@@ -197,6 +201,7 @@ public class RestApiServlet extends HttpServlet {
@Override
protected final void service(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
final long startNanos = System.nanoTime();
long auditStartTs = TimeUtil.nowMs();
res.setHeader("Content-Disposition", "attachment");
res.setHeader("X-Content-Type-Options", "nosniff");
@@ -389,6 +394,17 @@ public class RestApiServlet extends HttpServlet {
status = SC_INTERNAL_SERVER_ERROR;
handleException(e, req, res);
} finally {
String metric = viewData != null && viewData.view != null
? globals.metrics.view(viewData)
: "_unknown";
globals.metrics.count.increment(metric);
if (status >= SC_BAD_REQUEST) {
globals.metrics.errorCount.increment(metric, status);
}
globals.metrics.serverLatency.record(
metric,
System.nanoTime() - startNanos,
TimeUnit.NANOSECONDS);
globals.auditService.dispatch(new ExtendedHttpAuditEvent(globals.webSession.get()
.getSessionId(), globals.currentUser.get(), req,
auditStartTs, params, inputRequestBody, status,
@@ -1099,7 +1115,7 @@ public class RestApiServlet extends HttpServlet {
}
}
private static class ViewData {
static class ViewData {
String pluginName;
RestView<RestResource> view;