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:
		@@ -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;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -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;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user