DropWizard metric support
Gerrit server supports defining and recording metrics. Metric reporters for monitoring can be implemented as plugins. A basic Graphite reporter is available here: https://gerrit-review.googlesource.com/#/c/72202/ Some example metrics are included in this change: change/query/query_latency (Query latency) sshd/sessions/connected (SSH sessions connected) sshd/sessions/created/count (SSH connections created) git/upload-pack (Upload packs requests) Partially-by: Gustaf Lundh <gustaflh@axis.com> Change-Id: I46a07aace57efe236ee724ec8d34c581e2c37965
This commit is contained in:
		@@ -30,6 +30,7 @@ import com.google.gerrit.server.git.GitRepositoryManager;
 | 
				
			|||||||
import com.google.gerrit.server.git.ReceiveCommits;
 | 
					import com.google.gerrit.server.git.ReceiveCommits;
 | 
				
			||||||
import com.google.gerrit.server.git.TagCache;
 | 
					import com.google.gerrit.server.git.TagCache;
 | 
				
			||||||
import com.google.gerrit.server.git.TransferConfig;
 | 
					import com.google.gerrit.server.git.TransferConfig;
 | 
				
			||||||
 | 
					import com.google.gerrit.server.git.UploadPackMetricsHook;
 | 
				
			||||||
import com.google.gerrit.server.git.VisibleRefFilter;
 | 
					import com.google.gerrit.server.git.VisibleRefFilter;
 | 
				
			||||||
import com.google.gerrit.server.git.validators.UploadValidators;
 | 
					import com.google.gerrit.server.git.validators.UploadValidators;
 | 
				
			||||||
import com.google.gerrit.server.project.NoSuchProjectException;
 | 
					import com.google.gerrit.server.project.NoSuchProjectException;
 | 
				
			||||||
@@ -196,11 +197,15 @@ public class GitOverHttpServlet extends GitServlet {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  static class UploadFactory implements UploadPackFactory<HttpServletRequest> {
 | 
					  static class UploadFactory implements UploadPackFactory<HttpServletRequest> {
 | 
				
			||||||
    private final TransferConfig config;
 | 
					    private final TransferConfig config;
 | 
				
			||||||
 | 
					    private final UploadPackMetricsHook uploadMetrics;
 | 
				
			||||||
    private final DynamicSet<PreUploadHook> preUploadHooks;
 | 
					    private final DynamicSet<PreUploadHook> preUploadHooks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Inject
 | 
					    @Inject
 | 
				
			||||||
    UploadFactory(TransferConfig tc, DynamicSet<PreUploadHook> preUploadHooks) {
 | 
					    UploadFactory(TransferConfig tc,
 | 
				
			||||||
 | 
					        UploadPackMetricsHook uploadMetrics,
 | 
				
			||||||
 | 
					        DynamicSet<PreUploadHook> preUploadHooks) {
 | 
				
			||||||
      this.config = tc;
 | 
					      this.config = tc;
 | 
				
			||||||
 | 
					      this.uploadMetrics = uploadMetrics;
 | 
				
			||||||
      this.preUploadHooks = preUploadHooks;
 | 
					      this.preUploadHooks = preUploadHooks;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -211,6 +216,7 @@ public class GitOverHttpServlet extends GitServlet {
 | 
				
			|||||||
      up.setTimeout(config.getTimeout());
 | 
					      up.setTimeout(config.getTimeout());
 | 
				
			||||||
      up.setPreUploadHook(PreUploadHookChain.newChain(
 | 
					      up.setPreUploadHook(PreUploadHookChain.newChain(
 | 
				
			||||||
          Lists.newArrayList(preUploadHooks)));
 | 
					          Lists.newArrayList(preUploadHooks)));
 | 
				
			||||||
 | 
					      up.setPostUploadHook(uploadMetrics);
 | 
				
			||||||
      return up;
 | 
					      return up;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,6 +36,7 @@ import com.google.gerrit.httpd.auth.openid.OpenIdModule;
 | 
				
			|||||||
import com.google.gerrit.httpd.plugins.HttpPluginModule;
 | 
					import com.google.gerrit.httpd.plugins.HttpPluginModule;
 | 
				
			||||||
import com.google.gerrit.lifecycle.LifecycleManager;
 | 
					import com.google.gerrit.lifecycle.LifecycleManager;
 | 
				
			||||||
import com.google.gerrit.lucene.LuceneIndexModule;
 | 
					import com.google.gerrit.lucene.LuceneIndexModule;
 | 
				
			||||||
 | 
					import com.google.gerrit.metrics.dropwizard.DropWizardMetricMaker;
 | 
				
			||||||
import com.google.gerrit.pgm.http.jetty.JettyEnv;
 | 
					import com.google.gerrit.pgm.http.jetty.JettyEnv;
 | 
				
			||||||
import com.google.gerrit.pgm.http.jetty.JettyModule;
 | 
					import com.google.gerrit.pgm.http.jetty.JettyModule;
 | 
				
			||||||
import com.google.gerrit.pgm.http.jetty.ProjectQoSFilter;
 | 
					import com.google.gerrit.pgm.http.jetty.ProjectQoSFilter;
 | 
				
			||||||
@@ -323,6 +324,7 @@ public class Daemon extends SiteProgram {
 | 
				
			|||||||
  private Injector createSysInjector() {
 | 
					  private Injector createSysInjector() {
 | 
				
			||||||
    final List<Module> modules = new ArrayList<>();
 | 
					    final List<Module> modules = new ArrayList<>();
 | 
				
			||||||
    modules.add(SchemaVersionCheck.module());
 | 
					    modules.add(SchemaVersionCheck.module());
 | 
				
			||||||
 | 
					    modules.add(new DropWizardMetricMaker.Module());
 | 
				
			||||||
    modules.add(new LogFileCompressor.Module());
 | 
					    modules.add(new LogFileCompressor.Module());
 | 
				
			||||||
    modules.add(new WorkQueue.Module());
 | 
					    modules.add(new WorkQueue.Module());
 | 
				
			||||||
    modules.add(new ChangeHookRunner.Module());
 | 
					    modules.add(new ChangeHookRunner.Module());
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -53,6 +53,7 @@ java_library(
 | 
				
			|||||||
    '//lib/commons:lang',
 | 
					    '//lib/commons:lang',
 | 
				
			||||||
    '//lib/commons:net',
 | 
					    '//lib/commons:net',
 | 
				
			||||||
    '//lib/commons:validator',
 | 
					    '//lib/commons:validator',
 | 
				
			||||||
 | 
					    '//lib/dropwizard:dropwizard-core',
 | 
				
			||||||
    '//lib/guice:guice',
 | 
					    '//lib/guice:guice',
 | 
				
			||||||
    '//lib/guice:guice-assistedinject',
 | 
					    '//lib/guice:guice-assistedinject',
 | 
				
			||||||
    '//lib/guice:guice-servlet',
 | 
					    '//lib/guice:guice-servlet',
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,43 @@
 | 
				
			|||||||
 | 
					// 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.metrics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.google.gerrit.extensions.registration.RegistrationHandle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Metric whose value is supplied when the trigger is invoked.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * <pre>
 | 
				
			||||||
 | 
					 *   CallbackMetric<Long> hits = metricMaker.newCallbackMetric("hits", ...);
 | 
				
			||||||
 | 
					 *   CallbackMetric<Long> total = metricMaker.newCallbackMetric("total", ...);
 | 
				
			||||||
 | 
					 *   metricMaker.newTrigger(hits, total, new Runnable() {
 | 
				
			||||||
 | 
					 *     public void run() {
 | 
				
			||||||
 | 
					 *       hits.set(1);
 | 
				
			||||||
 | 
					 *       total.set(5);
 | 
				
			||||||
 | 
					 *     }
 | 
				
			||||||
 | 
					 *   });
 | 
				
			||||||
 | 
					 * </pre>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param <V> type of the metric value, typically Integer or Long.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public abstract class CallbackMetric<V> implements RegistrationHandle {
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Supply the current value of the metric.
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * @param value current value.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  public abstract void set(V value);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,41 @@
 | 
				
			|||||||
 | 
					// 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.metrics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.google.gerrit.extensions.registration.RegistrationHandle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Metric whose value increments during the life of the process.
 | 
				
			||||||
 | 
					 * <p>
 | 
				
			||||||
 | 
					 * Suitable uses are "total requests handled", "bytes sent", etc.
 | 
				
			||||||
 | 
					 * Use {@link Description#setRate()} to suggest the monitoring system
 | 
				
			||||||
 | 
					 * should also track the rate of increments if this is of interest.
 | 
				
			||||||
 | 
					 * <p>
 | 
				
			||||||
 | 
					 * For an instantaneous read of a value that can change over time
 | 
				
			||||||
 | 
					 * (e.g. "memory in use") use a {@link CallbackMetric}.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public abstract class Counter implements RegistrationHandle {
 | 
				
			||||||
 | 
					  /** Increment the counter by one event. */
 | 
				
			||||||
 | 
					  public void increment() {
 | 
				
			||||||
 | 
					    incrementBy(1);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Increment the counter by a specified amount.
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * @param value value to increment by, must be >= 0.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  public abstract void incrementBy(long value);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,141 @@
 | 
				
			|||||||
 | 
					// 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.metrics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.google.common.collect.ImmutableMap;
 | 
				
			||||||
 | 
					import com.google.common.collect.Maps;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.Map;
 | 
				
			||||||
 | 
					import java.util.concurrent.TimeUnit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Describes a metric created by {@link MetricMaker}. */
 | 
				
			||||||
 | 
					public class Description {
 | 
				
			||||||
 | 
					  public static final String DESCRIPTION = "DESCRIPTION";
 | 
				
			||||||
 | 
					  public static final String UNIT = "UNIT";
 | 
				
			||||||
 | 
					  public static final String CUMULATIVE = "CUMULATIVE";
 | 
				
			||||||
 | 
					  public static final String RATE = "RATE";
 | 
				
			||||||
 | 
					  public static final String GAUGE = "GAUGE";
 | 
				
			||||||
 | 
					  public static final String TRUE_VALUE = "1";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public static class Units {
 | 
				
			||||||
 | 
					    public static final String SECONDS = "seconds";
 | 
				
			||||||
 | 
					    public static final String MILLISECONDS = "milliseconds";
 | 
				
			||||||
 | 
					    public static final String MICROSECONDS = "microseconds";
 | 
				
			||||||
 | 
					    public static final String NANOSECONDS = "nanoseconds";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static final String BYTES = "bytes";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private Units() {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private final Map<String, String> annotations;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Describe a metric.
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * @param helpText a short one-sentence string explaining the values captured
 | 
				
			||||||
 | 
					   *        by the metric. This may be made available to administrators as
 | 
				
			||||||
 | 
					   *        documentation in the reporting tools.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  public Description(String helpText) {
 | 
				
			||||||
 | 
					    annotations = Maps.newLinkedHashMapWithExpectedSize(4);
 | 
				
			||||||
 | 
					    annotations.put(DESCRIPTION, helpText);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** Unit used to describe the value, e.g. "requests", "seconds", etc. */
 | 
				
			||||||
 | 
					  public Description setUnit(String unitName) {
 | 
				
			||||||
 | 
					    annotations.put(UNIT, unitName);
 | 
				
			||||||
 | 
					    return this;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Indicates the metric may be usefully interpreted as a count over short
 | 
				
			||||||
 | 
					   * periods of time, such as request arrival rate. May only be applied to a
 | 
				
			||||||
 | 
					   * {@link Counter}.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  public Description setRate() {
 | 
				
			||||||
 | 
					    annotations.put(RATE, TRUE_VALUE);
 | 
				
			||||||
 | 
					    return this;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Instantaneously sampled value that may increase or decrease at a later
 | 
				
			||||||
 | 
					   * time. Memory allocated or open network connections are examples of gauges.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  public Description setGauge() {
 | 
				
			||||||
 | 
					    annotations.put(GAUGE, TRUE_VALUE);
 | 
				
			||||||
 | 
					    return this;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Indicates the metric accumulates over the lifespan of the process. A
 | 
				
			||||||
 | 
					   * {@link Counter} like total requests handled accumulates over the process
 | 
				
			||||||
 | 
					   * and should be {@code setCumulative()}.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  public Description setCumulative() {
 | 
				
			||||||
 | 
					    annotations.put(CUMULATIVE, TRUE_VALUE);
 | 
				
			||||||
 | 
					    return this;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** True if the metric may be interpreted as a rate over time. */
 | 
				
			||||||
 | 
					  public boolean isRate() {
 | 
				
			||||||
 | 
					    return TRUE_VALUE.equals(annotations.get(RATE));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** True if the metric is an instantaneous sample. */
 | 
				
			||||||
 | 
					  public boolean isGauge() {
 | 
				
			||||||
 | 
					    return TRUE_VALUE.equals(annotations.get(GAUGE));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** True if the metric accumulates over the lifespan of the process. */
 | 
				
			||||||
 | 
					  public boolean isCumulative() {
 | 
				
			||||||
 | 
					    return TRUE_VALUE.equals(annotations.get(CUMULATIVE));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Decode the unit as a unit of time.
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * @return valid time unit.
 | 
				
			||||||
 | 
					   * @throws IllegalStateException if the unit is not a valid unit of time.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  public TimeUnit getTimeUnit() {
 | 
				
			||||||
 | 
					    String unit = annotations.get(UNIT);
 | 
				
			||||||
 | 
					    if (unit == null) {
 | 
				
			||||||
 | 
					      throw new IllegalStateException("no unit configured");
 | 
				
			||||||
 | 
					    } else if (Units.NANOSECONDS.equals(unit)) {
 | 
				
			||||||
 | 
					      return TimeUnit.NANOSECONDS;
 | 
				
			||||||
 | 
					    } else if (Units.MICROSECONDS.equals(unit)) {
 | 
				
			||||||
 | 
					      return TimeUnit.MICROSECONDS;
 | 
				
			||||||
 | 
					    } else if (Units.MILLISECONDS.equals(unit)) {
 | 
				
			||||||
 | 
					      return TimeUnit.MILLISECONDS;
 | 
				
			||||||
 | 
					    } else if (Units.SECONDS.equals(unit)) {
 | 
				
			||||||
 | 
					      return TimeUnit.SECONDS;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      throw new IllegalStateException(String.format(
 | 
				
			||||||
 | 
					          "unit %s not TimeUnit", unit));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** Immutable copy of all annotations (configurable properties). */
 | 
				
			||||||
 | 
					  public ImmutableMap<String, String> getAnnotations() {
 | 
				
			||||||
 | 
					    return ImmutableMap.copyOf(annotations);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Override
 | 
				
			||||||
 | 
					  public String toString() {
 | 
				
			||||||
 | 
					    return annotations.toString();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,83 @@
 | 
				
			|||||||
 | 
					// 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.metrics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.google.common.base.Supplier;
 | 
				
			||||||
 | 
					import com.google.common.collect.ImmutableSet;
 | 
				
			||||||
 | 
					import com.google.gerrit.extensions.registration.RegistrationHandle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.Set;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Factory to create metrics for monitoring. */
 | 
				
			||||||
 | 
					public abstract class MetricMaker {
 | 
				
			||||||
 | 
					  /** Metric whose value increments during the life of the process. */
 | 
				
			||||||
 | 
					  public abstract Counter newCounter(String name, Description desc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** Metric recording time spent on an operation. */
 | 
				
			||||||
 | 
					  public abstract Timer newTimer(String name, Description desc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Instantaneous reading of a value.
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * <pre>
 | 
				
			||||||
 | 
					   * metricMaker.newCallbackMetric("memory",
 | 
				
			||||||
 | 
					   *     new Description("Total bytes of memory used")
 | 
				
			||||||
 | 
					   *        .setGauge()
 | 
				
			||||||
 | 
					   *        .setUnit(Units.BYTES),
 | 
				
			||||||
 | 
					   *     new Supplier<Long>() {
 | 
				
			||||||
 | 
					   *       public Long get() {
 | 
				
			||||||
 | 
					   *         return Runtime.getRuntime().totalMemory();
 | 
				
			||||||
 | 
					   *       }
 | 
				
			||||||
 | 
					   *     });
 | 
				
			||||||
 | 
					   * </pre>
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * @param name unique name of the metric.
 | 
				
			||||||
 | 
					   * @param valueClass type of value recorded by the metric.
 | 
				
			||||||
 | 
					   * @param desc description of the metric.
 | 
				
			||||||
 | 
					   * @param trigger function to compute the value of the metric.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  public <V> void newCallbackMetric(String name,
 | 
				
			||||||
 | 
					      Class<V> valueClass, Description desc, final Supplier<V> trigger) {
 | 
				
			||||||
 | 
					    final CallbackMetric<V> metric = newCallbackMetric(name, valueClass, desc);
 | 
				
			||||||
 | 
					    newTrigger(metric, new Runnable() {
 | 
				
			||||||
 | 
					      @Override
 | 
				
			||||||
 | 
					      public void run() {
 | 
				
			||||||
 | 
					        metric.set(trigger.get());
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** Instantaneous reading of a particular value. */
 | 
				
			||||||
 | 
					  public abstract <V> CallbackMetric<V> newCallbackMetric(String name,
 | 
				
			||||||
 | 
					      Class<V> valueClass, Description desc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** Connect logic to populate a previously created {@link CallbackMetric}. */
 | 
				
			||||||
 | 
					  public RegistrationHandle newTrigger(CallbackMetric<?> metric1, Runnable trigger) {
 | 
				
			||||||
 | 
					    return newTrigger(ImmutableSet.<CallbackMetric<?>>of(metric1), trigger);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public RegistrationHandle newTrigger(CallbackMetric<?> metric1,
 | 
				
			||||||
 | 
					      CallbackMetric<?> metric2, Runnable trigger) {
 | 
				
			||||||
 | 
					    return newTrigger(ImmutableSet.of(metric1, metric2), trigger);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public RegistrationHandle newTrigger(CallbackMetric<?> metric1,
 | 
				
			||||||
 | 
					      CallbackMetric<?> metric2, CallbackMetric<?> metric3, Runnable trigger) {
 | 
				
			||||||
 | 
					    return newTrigger(ImmutableSet.of(metric1, metric2, metric3), trigger);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public abstract RegistrationHandle newTrigger(Set<CallbackMetric<?>> metrics,
 | 
				
			||||||
 | 
					      Runnable trigger);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,54 @@
 | 
				
			|||||||
 | 
					// 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.metrics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import static java.util.concurrent.TimeUnit.NANOSECONDS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.google.gerrit.extensions.registration.RegistrationHandle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.concurrent.TimeUnit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Records elapsed time for an operation or span.
 | 
				
			||||||
 | 
					 * <p>
 | 
				
			||||||
 | 
					 * Typical usage in a try-with-resources block:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * <pre>
 | 
				
			||||||
 | 
					 * try (Timer.Context ctx = timer.start()) {
 | 
				
			||||||
 | 
					 * }
 | 
				
			||||||
 | 
					 * </pre>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public abstract class Timer implements RegistrationHandle {
 | 
				
			||||||
 | 
					  public class Context implements AutoCloseable {
 | 
				
			||||||
 | 
					    private final long startNanos;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Context() {
 | 
				
			||||||
 | 
					      this.startNanos = System.nanoTime();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void close() {
 | 
				
			||||||
 | 
					      record(System.nanoTime() - startNanos, NANOSECONDS);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** Begin a timer for the current block, value will be recorded when closed. */
 | 
				
			||||||
 | 
					  public Context start() {
 | 
				
			||||||
 | 
					    return new Context();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** Record a value in the distribution. */
 | 
				
			||||||
 | 
					  public abstract void record(long value, TimeUnit unit);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,205 @@
 | 
				
			|||||||
 | 
					// 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.metrics.dropwizard;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import static com.google.common.base.Preconditions.checkArgument;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.google.gerrit.extensions.registration.RegistrationHandle;
 | 
				
			||||||
 | 
					import com.google.gerrit.metrics.CallbackMetric;
 | 
				
			||||||
 | 
					import com.google.gerrit.metrics.Counter;
 | 
				
			||||||
 | 
					import com.google.gerrit.metrics.Description;
 | 
				
			||||||
 | 
					import com.google.gerrit.metrics.MetricMaker;
 | 
				
			||||||
 | 
					import com.google.gerrit.metrics.Timer;
 | 
				
			||||||
 | 
					import com.google.inject.AbstractModule;
 | 
				
			||||||
 | 
					import com.google.inject.Inject;
 | 
				
			||||||
 | 
					import com.google.inject.Scopes;
 | 
				
			||||||
 | 
					import com.google.inject.Singleton;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.codahale.metrics.MetricRegistry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.ArrayList;
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					import java.util.Set;
 | 
				
			||||||
 | 
					import java.util.concurrent.TimeUnit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Connects Gerrit metric package onto DropWizard.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @see <a href="http://www.dropwizard.io/">DropWizard</a>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@Singleton
 | 
				
			||||||
 | 
					public class DropWizardMetricMaker extends MetricMaker {
 | 
				
			||||||
 | 
					  public static class Module extends AbstractModule {
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    protected void configure() {
 | 
				
			||||||
 | 
					      bind(MetricRegistry.class).in(Scopes.SINGLETON);
 | 
				
			||||||
 | 
					      bind(MetricMaker.class).to(DropWizardMetricMaker.class);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private final MetricRegistry registry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Inject
 | 
				
			||||||
 | 
					  DropWizardMetricMaker(MetricRegistry registry) {
 | 
				
			||||||
 | 
					    this.registry = registry;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Override
 | 
				
			||||||
 | 
					  public synchronized Counter newCounter(String name, Description desc) {
 | 
				
			||||||
 | 
					    checkArgument(!desc.isGauge(), "counters must not be gauge");
 | 
				
			||||||
 | 
					    checkNotDefined(name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (desc.isRate()) {
 | 
				
			||||||
 | 
					      final com.codahale.metrics.Meter metric = registry.meter(name);
 | 
				
			||||||
 | 
					      return new CounterImpl(name) {
 | 
				
			||||||
 | 
					        @Override
 | 
				
			||||||
 | 
					        public void incrementBy(long delta) {
 | 
				
			||||||
 | 
					          checkArgument(delta >= 0, "counter delta must be >= 0");
 | 
				
			||||||
 | 
					          metric.mark(delta);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      final com.codahale.metrics.Counter metric = registry.counter(name);
 | 
				
			||||||
 | 
					      return new CounterImpl(name) {
 | 
				
			||||||
 | 
					        @Override
 | 
				
			||||||
 | 
					        public void incrementBy(long delta) {
 | 
				
			||||||
 | 
					          checkArgument(delta >= 0, "counter delta must be >= 0");
 | 
				
			||||||
 | 
					          metric.inc(delta);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Override
 | 
				
			||||||
 | 
					  public synchronized Timer newTimer(final String name, Description desc) {
 | 
				
			||||||
 | 
					    checkArgument(!desc.isGauge(), "timer must not be a gauge");
 | 
				
			||||||
 | 
					    checkArgument(!desc.isRate(), "timer must not be a rate");
 | 
				
			||||||
 | 
					    checkArgument(desc.isCumulative(), "timer must be cumulative");
 | 
				
			||||||
 | 
					    checkArgument(desc.getTimeUnit() != null, "timer must have a unit");
 | 
				
			||||||
 | 
					    checkNotDefined(name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    final com.codahale.metrics.Timer metric = registry.timer(name);
 | 
				
			||||||
 | 
					    return new Timer() {
 | 
				
			||||||
 | 
					      @Override
 | 
				
			||||||
 | 
					      public void record(long value, TimeUnit unit) {
 | 
				
			||||||
 | 
					        checkArgument(value >= 0, "timer delta must be >= 0");
 | 
				
			||||||
 | 
					        metric.update(value, unit);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      @Override
 | 
				
			||||||
 | 
					      public void remove() {
 | 
				
			||||||
 | 
					        registry.remove(name);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @SuppressWarnings("unused")
 | 
				
			||||||
 | 
					  @Override
 | 
				
			||||||
 | 
					  public <V> CallbackMetric<V> newCallbackMetric(String name,
 | 
				
			||||||
 | 
					      Class<V> valueClass, Description desc) {
 | 
				
			||||||
 | 
					    checkNotDefined(name);
 | 
				
			||||||
 | 
					    return new CallbackMetricImpl<V>(name, valueClass);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Override
 | 
				
			||||||
 | 
					  public synchronized RegistrationHandle newTrigger(
 | 
				
			||||||
 | 
					      Set<CallbackMetric<?>> metrics, Runnable trigger) {
 | 
				
			||||||
 | 
					    for (CallbackMetric<?> m : metrics) {
 | 
				
			||||||
 | 
					      checkNotDefined(((CallbackMetricImpl<?>) m).name);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    final List<String> names = new ArrayList<>(metrics.size());
 | 
				
			||||||
 | 
					    for (CallbackMetric<?> m : metrics) {
 | 
				
			||||||
 | 
					      CallbackMetricImpl<?> metric = (CallbackMetricImpl<?>) m;
 | 
				
			||||||
 | 
					      registry.register(metric.name, metric.gauge(trigger));
 | 
				
			||||||
 | 
					      names.add(metric.name);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return new RegistrationHandle() {
 | 
				
			||||||
 | 
					      @Override
 | 
				
			||||||
 | 
					      public void remove() {
 | 
				
			||||||
 | 
					        for (String name : names) {
 | 
				
			||||||
 | 
					          registry.remove(name);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private void checkNotDefined(String name) {
 | 
				
			||||||
 | 
					    if (registry.getNames().contains(name)) {
 | 
				
			||||||
 | 
					      throw new IllegalStateException(String.format(
 | 
				
			||||||
 | 
					          "metric %s already defined", name));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private abstract class CounterImpl extends Counter {
 | 
				
			||||||
 | 
					    private final String name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    CounterImpl(String name) {
 | 
				
			||||||
 | 
					      this.name = name;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void remove() {
 | 
				
			||||||
 | 
					      registry.remove(name);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private static class CallbackMetricImpl<V> extends CallbackMetric<V> {
 | 
				
			||||||
 | 
					    private final String name;
 | 
				
			||||||
 | 
					    private V value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @SuppressWarnings("unchecked")
 | 
				
			||||||
 | 
					    CallbackMetricImpl(String name, Class<V> valueClass) {
 | 
				
			||||||
 | 
					      this.name = name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (valueClass == Integer.class) {
 | 
				
			||||||
 | 
					        value = (V) Integer.valueOf(0);
 | 
				
			||||||
 | 
					      } else if (valueClass == Long.class) {
 | 
				
			||||||
 | 
					        value = (V) Long.valueOf(0);
 | 
				
			||||||
 | 
					      } else if (valueClass == Double.class) {
 | 
				
			||||||
 | 
					        value = (V) Double.valueOf(0);
 | 
				
			||||||
 | 
					      } else if (valueClass == Float.class) {
 | 
				
			||||||
 | 
					        value = (V) Float.valueOf(0);
 | 
				
			||||||
 | 
					      } else if (valueClass == String.class) {
 | 
				
			||||||
 | 
					        value = (V) "";
 | 
				
			||||||
 | 
					      } else if (valueClass == Boolean.class) {
 | 
				
			||||||
 | 
					        value = (V) Boolean.FALSE;
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        throw new IllegalArgumentException("unsupported value type "
 | 
				
			||||||
 | 
					            + valueClass.getName());
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void set(V value) {
 | 
				
			||||||
 | 
					      this.value = value;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void remove() {
 | 
				
			||||||
 | 
					      // Triggers register and remove the metric.
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    com.codahale.metrics.Gauge<V> gauge(final Runnable trigger) {
 | 
				
			||||||
 | 
					      return new com.codahale.metrics.Gauge<V>() {
 | 
				
			||||||
 | 
					        @Override
 | 
				
			||||||
 | 
					        public V getValue() {
 | 
				
			||||||
 | 
					          trigger.run();
 | 
				
			||||||
 | 
					          return value;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,43 @@
 | 
				
			|||||||
 | 
					// 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.server.git;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.google.gerrit.metrics.Counter;
 | 
				
			||||||
 | 
					import com.google.gerrit.metrics.Description;
 | 
				
			||||||
 | 
					import com.google.gerrit.metrics.MetricMaker;
 | 
				
			||||||
 | 
					import com.google.inject.Inject;
 | 
				
			||||||
 | 
					import com.google.inject.Singleton;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.eclipse.jgit.storage.pack.PackStatistics;
 | 
				
			||||||
 | 
					import org.eclipse.jgit.transport.PostUploadHook;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Singleton
 | 
				
			||||||
 | 
					public class UploadPackMetricsHook implements PostUploadHook {
 | 
				
			||||||
 | 
					  private final Counter upload;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Inject
 | 
				
			||||||
 | 
					  UploadPackMetricsHook(MetricMaker metricMaker) {
 | 
				
			||||||
 | 
					    upload = metricMaker.newCounter(
 | 
				
			||||||
 | 
					        "git/upload-pack",
 | 
				
			||||||
 | 
					        new Description("Total number of git-upload-pack requests")
 | 
				
			||||||
 | 
					          .setRate()
 | 
				
			||||||
 | 
					          .setUnit("requests"));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Override
 | 
				
			||||||
 | 
					  public void onPostUpload(PackStatistics stats) {
 | 
				
			||||||
 | 
					    upload.increment();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -34,6 +34,7 @@ import com.google.gerrit.extensions.registration.PrivateInternals_DynamicTypes;
 | 
				
			|||||||
import com.google.gerrit.extensions.registration.RegistrationHandle;
 | 
					import com.google.gerrit.extensions.registration.RegistrationHandle;
 | 
				
			||||||
import com.google.gerrit.extensions.registration.ReloadableRegistrationHandle;
 | 
					import com.google.gerrit.extensions.registration.ReloadableRegistrationHandle;
 | 
				
			||||||
import com.google.gerrit.extensions.systemstatus.ServerInformation;
 | 
					import com.google.gerrit.extensions.systemstatus.ServerInformation;
 | 
				
			||||||
 | 
					import com.google.gerrit.metrics.MetricMaker;
 | 
				
			||||||
import com.google.gerrit.server.util.PluginRequestContext;
 | 
					import com.google.gerrit.server.util.PluginRequestContext;
 | 
				
			||||||
import com.google.gerrit.server.util.RequestContext;
 | 
					import com.google.gerrit.server.util.RequestContext;
 | 
				
			||||||
import com.google.gerrit.server.util.ThreadLocalRequestContext;
 | 
					import com.google.gerrit.server.util.ThreadLocalRequestContext;
 | 
				
			||||||
@@ -77,6 +78,7 @@ public class PluginGuiceEnvironment {
 | 
				
			|||||||
  private final List<StartPluginListener> onStart;
 | 
					  private final List<StartPluginListener> onStart;
 | 
				
			||||||
  private final List<StopPluginListener> onStop;
 | 
					  private final List<StopPluginListener> onStop;
 | 
				
			||||||
  private final List<ReloadPluginListener> onReload;
 | 
					  private final List<ReloadPluginListener> onReload;
 | 
				
			||||||
 | 
					  private final MetricMaker serverMetrics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private Module sysModule;
 | 
					  private Module sysModule;
 | 
				
			||||||
  private Module sshModule;
 | 
					  private Module sshModule;
 | 
				
			||||||
@@ -102,12 +104,14 @@ public class PluginGuiceEnvironment {
 | 
				
			|||||||
      Injector sysInjector,
 | 
					      Injector sysInjector,
 | 
				
			||||||
      ThreadLocalRequestContext local,
 | 
					      ThreadLocalRequestContext local,
 | 
				
			||||||
      ServerInformation srvInfo,
 | 
					      ServerInformation srvInfo,
 | 
				
			||||||
      CopyConfigModule ccm) {
 | 
					      CopyConfigModule ccm,
 | 
				
			||||||
 | 
					      MetricMaker serverMetrics) {
 | 
				
			||||||
    this.sysInjector = sysInjector;
 | 
					    this.sysInjector = sysInjector;
 | 
				
			||||||
    this.srvInfo = srvInfo;
 | 
					    this.srvInfo = srvInfo;
 | 
				
			||||||
    this.local = local;
 | 
					    this.local = local;
 | 
				
			||||||
    this.copyConfigModule = ccm;
 | 
					    this.copyConfigModule = ccm;
 | 
				
			||||||
    this.copyConfigKeys = Guice.createInjector(ccm).getAllBindings().keySet();
 | 
					    this.copyConfigKeys = Guice.createInjector(ccm).getAllBindings().keySet();
 | 
				
			||||||
 | 
					    this.serverMetrics = serverMetrics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    onStart = new CopyOnWriteArrayList<>();
 | 
					    onStart = new CopyOnWriteArrayList<>();
 | 
				
			||||||
    onStart.addAll(listeners(sysInjector, StartPluginListener.class));
 | 
					    onStart.addAll(listeners(sysInjector, StartPluginListener.class));
 | 
				
			||||||
@@ -127,6 +131,10 @@ public class PluginGuiceEnvironment {
 | 
				
			|||||||
    return srvInfo;
 | 
					    return srvInfo;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  MetricMaker getServerMetrics() {
 | 
				
			||||||
 | 
					    return serverMetrics;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  boolean hasDynamicItem(TypeLiteral<?> type) {
 | 
					  boolean hasDynamicItem(TypeLiteral<?> type) {
 | 
				
			||||||
    return sysItems.containsKey(type)
 | 
					    return sysItems.containsKey(type)
 | 
				
			||||||
        || (sshItems != null && sshItems.containsKey(type))
 | 
					        || (sshItems != null && sshItems.containsKey(type))
 | 
				
			||||||
@@ -424,6 +432,7 @@ public class PluginGuiceEnvironment {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private void reattachItem(
 | 
					  private void reattachItem(
 | 
				
			||||||
      ListMultimap<TypeLiteral<?>, ReloadableRegistrationHandle<?>> oldHandles,
 | 
					      ListMultimap<TypeLiteral<?>, ReloadableRegistrationHandle<?>> oldHandles,
 | 
				
			||||||
      Map<TypeLiteral<?>, DynamicItem<?>> items,
 | 
					      Map<TypeLiteral<?>, DynamicItem<?>> items,
 | 
				
			||||||
@@ -564,6 +573,9 @@ public class PluginGuiceEnvironment {
 | 
				
			|||||||
    if (StopPluginListener.class.isAssignableFrom(type)) {
 | 
					    if (StopPluginListener.class.isAssignableFrom(type)) {
 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    if (MetricMaker.class.isAssignableFrom(type)) {
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (type.getName().startsWith("com.google.inject.")) {
 | 
					    if (type.getName().startsWith("com.google.inject.")) {
 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,91 @@
 | 
				
			|||||||
 | 
					// 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.server.plugins;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.google.gerrit.extensions.events.LifecycleListener;
 | 
				
			||||||
 | 
					import com.google.gerrit.extensions.registration.RegistrationHandle;
 | 
				
			||||||
 | 
					import com.google.gerrit.metrics.CallbackMetric;
 | 
				
			||||||
 | 
					import com.google.gerrit.metrics.Counter;
 | 
				
			||||||
 | 
					import com.google.gerrit.metrics.Description;
 | 
				
			||||||
 | 
					import com.google.gerrit.metrics.MetricMaker;
 | 
				
			||||||
 | 
					import com.google.gerrit.metrics.Timer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.Collections;
 | 
				
			||||||
 | 
					import java.util.HashSet;
 | 
				
			||||||
 | 
					import java.util.Iterator;
 | 
				
			||||||
 | 
					import java.util.Set;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class PluginMetricMaker extends MetricMaker implements LifecycleListener {
 | 
				
			||||||
 | 
					  private final MetricMaker root;
 | 
				
			||||||
 | 
					  private final String prefix;
 | 
				
			||||||
 | 
					  private final Set<RegistrationHandle> cleanup;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  PluginMetricMaker(MetricMaker root, String pluginName) {
 | 
				
			||||||
 | 
					    this.root = root;
 | 
				
			||||||
 | 
					    this.prefix = "plugins/" + pluginName;
 | 
				
			||||||
 | 
					    cleanup = Collections.synchronizedSet(new HashSet<RegistrationHandle>());
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Override
 | 
				
			||||||
 | 
					  public Counter newCounter(String name, Description desc) {
 | 
				
			||||||
 | 
					    Counter m = root.newCounter(prefix + name, desc);
 | 
				
			||||||
 | 
					    cleanup.add(m);
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Override
 | 
				
			||||||
 | 
					  public Timer newTimer(String name, Description desc) {
 | 
				
			||||||
 | 
					    Timer m = root.newTimer(prefix + name, desc);
 | 
				
			||||||
 | 
					    cleanup.add(m);
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Override
 | 
				
			||||||
 | 
					  public <V> CallbackMetric<V> newCallbackMetric(String name,
 | 
				
			||||||
 | 
					      Class<V> valueClass, Description desc) {
 | 
				
			||||||
 | 
					    CallbackMetric<V> m = root.newCallbackMetric(prefix + name, valueClass, desc);
 | 
				
			||||||
 | 
					    cleanup.add(m);
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Override
 | 
				
			||||||
 | 
					  public RegistrationHandle newTrigger(Set<CallbackMetric<?>> metrics,
 | 
				
			||||||
 | 
					      Runnable trigger) {
 | 
				
			||||||
 | 
					    final RegistrationHandle handle = root.newTrigger(metrics, trigger);
 | 
				
			||||||
 | 
					    cleanup.add(handle);
 | 
				
			||||||
 | 
					    return new RegistrationHandle() {
 | 
				
			||||||
 | 
					      @Override
 | 
				
			||||||
 | 
					      public void remove() {
 | 
				
			||||||
 | 
					        handle.remove();
 | 
				
			||||||
 | 
					        cleanup.remove(handle);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Override
 | 
				
			||||||
 | 
					  public void start() {
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Override
 | 
				
			||||||
 | 
					  public void stop() {
 | 
				
			||||||
 | 
					    synchronized (cleanup) {
 | 
				
			||||||
 | 
					      Iterator<RegistrationHandle> itr = cleanup.iterator();
 | 
				
			||||||
 | 
					      while (itr.hasNext()) {
 | 
				
			||||||
 | 
					        itr.next().remove();
 | 
				
			||||||
 | 
					        itr.remove();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -236,7 +236,7 @@ public class ServerPlugin extends Plugin {
 | 
				
			|||||||
    if (getApiType() == ApiType.PLUGIN) {
 | 
					    if (getApiType() == ApiType.PLUGIN) {
 | 
				
			||||||
      modules.add(env.getSysModule());
 | 
					      modules.add(env.getSysModule());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    modules.add(new ServerPluginInfoModule(this));
 | 
					    modules.add(new ServerPluginInfoModule(this, env.getServerMetrics()));
 | 
				
			||||||
    return Guice.createInjector(modules);
 | 
					    return Guice.createInjector(modules);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,6 +17,8 @@ package com.google.gerrit.server.plugins;
 | 
				
			|||||||
import com.google.gerrit.extensions.annotations.PluginCanonicalWebUrl;
 | 
					import com.google.gerrit.extensions.annotations.PluginCanonicalWebUrl;
 | 
				
			||||||
import com.google.gerrit.extensions.annotations.PluginData;
 | 
					import com.google.gerrit.extensions.annotations.PluginData;
 | 
				
			||||||
import com.google.gerrit.extensions.annotations.PluginName;
 | 
					import com.google.gerrit.extensions.annotations.PluginName;
 | 
				
			||||||
 | 
					import com.google.gerrit.lifecycle.LifecycleModule;
 | 
				
			||||||
 | 
					import com.google.gerrit.metrics.MetricMaker;
 | 
				
			||||||
import com.google.gerrit.server.PluginUser;
 | 
					import com.google.gerrit.server.PluginUser;
 | 
				
			||||||
import com.google.inject.AbstractModule;
 | 
					import com.google.inject.AbstractModule;
 | 
				
			||||||
import com.google.inject.Provides;
 | 
					import com.google.inject.Provides;
 | 
				
			||||||
@@ -32,10 +34,12 @@ class ServerPluginInfoModule extends AbstractModule {
 | 
				
			|||||||
  private final Path dataDir;
 | 
					  private final Path dataDir;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private volatile boolean ready;
 | 
					  private volatile boolean ready;
 | 
				
			||||||
 | 
					  private final MetricMaker serverMetrics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ServerPluginInfoModule(ServerPlugin plugin) {
 | 
					  ServerPluginInfoModule(ServerPlugin plugin, MetricMaker serverMetrics) {
 | 
				
			||||||
    this.plugin = plugin;
 | 
					    this.plugin = plugin;
 | 
				
			||||||
    this.dataDir = plugin.getDataDir();
 | 
					    this.dataDir = plugin.getDataDir();
 | 
				
			||||||
 | 
					    this.serverMetrics = serverMetrics;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @Override
 | 
					  @Override
 | 
				
			||||||
@@ -47,6 +51,17 @@ class ServerPluginInfoModule extends AbstractModule {
 | 
				
			|||||||
    bind(String.class)
 | 
					    bind(String.class)
 | 
				
			||||||
      .annotatedWith(PluginCanonicalWebUrl.class)
 | 
					      .annotatedWith(PluginCanonicalWebUrl.class)
 | 
				
			||||||
      .toInstance(plugin.getPluginCanonicalWebUrl());
 | 
					      .toInstance(plugin.getPluginCanonicalWebUrl());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    install(new LifecycleModule() {
 | 
				
			||||||
 | 
					      @Override
 | 
				
			||||||
 | 
					      public void configure() {
 | 
				
			||||||
 | 
					        PluginMetricMaker metrics = new PluginMetricMaker(
 | 
				
			||||||
 | 
					            serverMetrics,
 | 
				
			||||||
 | 
					            plugin.getName());
 | 
				
			||||||
 | 
					        bind(MetricMaker.class).toInstance(metrics);
 | 
				
			||||||
 | 
					        listener().toInstance(metrics);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @Provides
 | 
					  @Provides
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,6 +20,9 @@ import static com.google.gerrit.server.query.change.ChangeStatusPredicate.open;
 | 
				
			|||||||
import com.google.common.collect.ImmutableList;
 | 
					import com.google.common.collect.ImmutableList;
 | 
				
			||||||
import com.google.common.collect.Ordering;
 | 
					import com.google.common.collect.Ordering;
 | 
				
			||||||
import com.google.gerrit.common.data.GlobalCapability;
 | 
					import com.google.gerrit.common.data.GlobalCapability;
 | 
				
			||||||
 | 
					import com.google.gerrit.metrics.Description;
 | 
				
			||||||
 | 
					import com.google.gerrit.metrics.MetricMaker;
 | 
				
			||||||
 | 
					import com.google.gerrit.metrics.Timer;
 | 
				
			||||||
import com.google.gerrit.reviewdb.server.ReviewDb;
 | 
					import com.google.gerrit.reviewdb.server.ReviewDb;
 | 
				
			||||||
import com.google.gerrit.server.CurrentUser;
 | 
					import com.google.gerrit.server.CurrentUser;
 | 
				
			||||||
import com.google.gerrit.server.index.IndexConfig;
 | 
					import com.google.gerrit.server.index.IndexConfig;
 | 
				
			||||||
@@ -32,6 +35,7 @@ import com.google.gwtorm.server.OrmException;
 | 
				
			|||||||
import com.google.gwtorm.server.ResultSet;
 | 
					import com.google.gwtorm.server.ResultSet;
 | 
				
			||||||
import com.google.inject.Inject;
 | 
					import com.google.inject.Inject;
 | 
				
			||||||
import com.google.inject.Provider;
 | 
					import com.google.inject.Provider;
 | 
				
			||||||
 | 
					import com.google.inject.Singleton;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.ArrayList;
 | 
					import java.util.ArrayList;
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
@@ -42,6 +46,7 @@ public class QueryProcessor {
 | 
				
			|||||||
  private final ChangeControl.GenericFactory changeControlFactory;
 | 
					  private final ChangeControl.GenericFactory changeControlFactory;
 | 
				
			||||||
  private final IndexRewriter rewriter;
 | 
					  private final IndexRewriter rewriter;
 | 
				
			||||||
  private final IndexConfig indexConfig;
 | 
					  private final IndexConfig indexConfig;
 | 
				
			||||||
 | 
					  private final Metrics metrics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private int limitFromCaller;
 | 
					  private int limitFromCaller;
 | 
				
			||||||
  private int start;
 | 
					  private int start;
 | 
				
			||||||
@@ -52,12 +57,14 @@ public class QueryProcessor {
 | 
				
			|||||||
      Provider<CurrentUser> userProvider,
 | 
					      Provider<CurrentUser> userProvider,
 | 
				
			||||||
      ChangeControl.GenericFactory changeControlFactory,
 | 
					      ChangeControl.GenericFactory changeControlFactory,
 | 
				
			||||||
      IndexRewriter rewriter,
 | 
					      IndexRewriter rewriter,
 | 
				
			||||||
      IndexConfig indexConfig) {
 | 
					      IndexConfig indexConfig,
 | 
				
			||||||
 | 
					      Metrics metrics) {
 | 
				
			||||||
    this.db = db;
 | 
					    this.db = db;
 | 
				
			||||||
    this.userProvider = userProvider;
 | 
					    this.userProvider = userProvider;
 | 
				
			||||||
    this.changeControlFactory = changeControlFactory;
 | 
					    this.changeControlFactory = changeControlFactory;
 | 
				
			||||||
    this.rewriter = rewriter;
 | 
					    this.rewriter = rewriter;
 | 
				
			||||||
    this.indexConfig = indexConfig;
 | 
					    this.indexConfig = indexConfig;
 | 
				
			||||||
 | 
					    this.metrics = metrics;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public QueryProcessor enforceVisibility(boolean enforce) {
 | 
					  public QueryProcessor enforceVisibility(boolean enforce) {
 | 
				
			||||||
@@ -114,6 +121,9 @@ public class QueryProcessor {
 | 
				
			|||||||
  private List<QueryResult> queryChanges(List<String> queryStrings,
 | 
					  private List<QueryResult> queryChanges(List<String> queryStrings,
 | 
				
			||||||
      List<Predicate<ChangeData>> queries)
 | 
					      List<Predicate<ChangeData>> queries)
 | 
				
			||||||
      throws OrmException, QueryParseException {
 | 
					      throws OrmException, QueryParseException {
 | 
				
			||||||
 | 
					    @SuppressWarnings("resource")
 | 
				
			||||||
 | 
					    Timer.Context context = metrics.executionTime.start();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Predicate<ChangeData> visibleToMe = enforceVisibility
 | 
					    Predicate<ChangeData> visibleToMe = enforceVisibility
 | 
				
			||||||
        ? new IsVisibleToPredicate(db, changeControlFactory, userProvider.get())
 | 
					        ? new IsVisibleToPredicate(db, changeControlFactory, userProvider.get())
 | 
				
			||||||
        : null;
 | 
					        : null;
 | 
				
			||||||
@@ -170,6 +180,7 @@ public class QueryProcessor {
 | 
				
			|||||||
          limits.get(i),
 | 
					          limits.get(i),
 | 
				
			||||||
          matches.get(i).toList()));
 | 
					          matches.get(i).toList()));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    context.close(); // only measure successful queries
 | 
				
			||||||
    return out;
 | 
					    return out;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -203,4 +214,19 @@ public class QueryProcessor {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    return Ordering.natural().min(possibleLimits);
 | 
					    return Ordering.natural().min(possibleLimits);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Singleton
 | 
				
			||||||
 | 
					  static class Metrics {
 | 
				
			||||||
 | 
					    final Timer executionTime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Inject
 | 
				
			||||||
 | 
					    Metrics(MetricMaker metricMaker) {
 | 
				
			||||||
 | 
					      executionTime = metricMaker.newTimer(
 | 
				
			||||||
 | 
					          "change/query/query_latency",
 | 
				
			||||||
 | 
					          new Description("Successful change query latency,"
 | 
				
			||||||
 | 
					              + " accumulated over the life of the process")
 | 
				
			||||||
 | 
					            .setCumulative()
 | 
				
			||||||
 | 
					            .setUnit(Description.Units.MILLISECONDS));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,6 +22,7 @@ import com.google.gerrit.common.ChangeHooks;
 | 
				
			|||||||
import com.google.gerrit.common.DisabledChangeHooks;
 | 
					import com.google.gerrit.common.DisabledChangeHooks;
 | 
				
			||||||
import com.google.gerrit.extensions.config.FactoryModule;
 | 
					import com.google.gerrit.extensions.config.FactoryModule;
 | 
				
			||||||
import com.google.gerrit.gpg.GpgModule;
 | 
					import com.google.gerrit.gpg.GpgModule;
 | 
				
			||||||
 | 
					import com.google.gerrit.metrics.dropwizard.DropWizardMetricMaker;
 | 
				
			||||||
import com.google.gerrit.reviewdb.client.AuthType;
 | 
					import com.google.gerrit.reviewdb.client.AuthType;
 | 
				
			||||||
import com.google.gerrit.reviewdb.server.ReviewDb;
 | 
					import com.google.gerrit.reviewdb.server.ReviewDb;
 | 
				
			||||||
import com.google.gerrit.server.GerritPersonIdent;
 | 
					import com.google.gerrit.server.GerritPersonIdent;
 | 
				
			||||||
@@ -132,6 +133,7 @@ public class InMemoryModule extends FactoryModule {
 | 
				
			|||||||
            .toInstance(cfg);
 | 
					            .toInstance(cfg);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					    install(new DropWizardMetricMaker.Module());
 | 
				
			||||||
    install(cfgInjector.getInstance(GerritGlobalModule.class));
 | 
					    install(cfgInjector.getInstance(GerritGlobalModule.class));
 | 
				
			||||||
    install(new ChangeCacheImplModule(false));
 | 
					    install(new ChangeCacheImplModule(false));
 | 
				
			||||||
    factory(GarbageCollection.Factory.class);
 | 
					    factory(GarbageCollection.Factory.class);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,6 +21,7 @@ java_library(
 | 
				
			|||||||
    '//lib/auto:auto-value',
 | 
					    '//lib/auto:auto-value',
 | 
				
			||||||
    '//lib/commons:codec',
 | 
					    '//lib/commons:codec',
 | 
				
			||||||
    '//lib/commons:collections',
 | 
					    '//lib/commons:collections',
 | 
				
			||||||
 | 
					    '//lib/dropwizard:dropwizard-core',
 | 
				
			||||||
    '//lib/guice:guice',
 | 
					    '//lib/guice:guice',
 | 
				
			||||||
    '//lib/guice:guice-assistedinject',
 | 
					    '//lib/guice:guice-assistedinject',
 | 
				
			||||||
    '//lib/guice:guice-servlet',  # SSH should not depend on servlet
 | 
					    '//lib/guice:guice-servlet',  # SSH should not depend on servlet
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,10 +19,14 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS;
 | 
				
			|||||||
import static java.util.concurrent.TimeUnit.SECONDS;
 | 
					import static java.util.concurrent.TimeUnit.SECONDS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.google.common.base.Strings;
 | 
					import com.google.common.base.Strings;
 | 
				
			||||||
 | 
					import com.google.common.base.Supplier;
 | 
				
			||||||
import com.google.common.collect.Iterables;
 | 
					import com.google.common.collect.Iterables;
 | 
				
			||||||
import com.google.common.collect.Lists;
 | 
					import com.google.common.collect.Lists;
 | 
				
			||||||
import com.google.gerrit.common.Version;
 | 
					import com.google.gerrit.common.Version;
 | 
				
			||||||
import com.google.gerrit.extensions.events.LifecycleListener;
 | 
					import com.google.gerrit.extensions.events.LifecycleListener;
 | 
				
			||||||
 | 
					import com.google.gerrit.metrics.Counter;
 | 
				
			||||||
 | 
					import com.google.gerrit.metrics.Description;
 | 
				
			||||||
 | 
					import com.google.gerrit.metrics.MetricMaker;
 | 
				
			||||||
import com.google.gerrit.server.config.ConfigUtil;
 | 
					import com.google.gerrit.server.config.ConfigUtil;
 | 
				
			||||||
import com.google.gerrit.server.config.GerritServerConfig;
 | 
					import com.google.gerrit.server.config.GerritServerConfig;
 | 
				
			||||||
import com.google.gerrit.server.ssh.SshAdvertisedAddresses;
 | 
					import com.google.gerrit.server.ssh.SshAdvertisedAddresses;
 | 
				
			||||||
@@ -126,6 +130,7 @@ import java.util.Collections;
 | 
				
			|||||||
import java.util.Iterator;
 | 
					import java.util.Iterator;
 | 
				
			||||||
import java.util.LinkedList;
 | 
					import java.util.LinkedList;
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					import java.util.concurrent.atomic.AtomicInteger;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * SSH daemon to communicate with Gerrit.
 | 
					 * SSH daemon to communicate with Gerrit.
 | 
				
			||||||
@@ -170,7 +175,8 @@ public class SshDaemon extends SshServer implements SshInfo, LifecycleListener {
 | 
				
			|||||||
      final KeyPairProvider hostKeyProvider, final IdGenerator idGenerator,
 | 
					      final KeyPairProvider hostKeyProvider, final IdGenerator idGenerator,
 | 
				
			||||||
      @GerritServerConfig final Config cfg, final SshLog sshLog,
 | 
					      @GerritServerConfig final Config cfg, final SshLog sshLog,
 | 
				
			||||||
      @SshListenAddresses final List<SocketAddress> listen,
 | 
					      @SshListenAddresses final List<SocketAddress> listen,
 | 
				
			||||||
      @SshAdvertisedAddresses final List<String> advertised) {
 | 
					      @SshAdvertisedAddresses final List<String> advertised,
 | 
				
			||||||
 | 
					      MetricMaker metricMaker) {
 | 
				
			||||||
    setPort(IANA_SSH_PORT /* never used */);
 | 
					    setPort(IANA_SSH_PORT /* never used */);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.cfg = cfg;
 | 
					    this.cfg = cfg;
 | 
				
			||||||
@@ -245,10 +251,33 @@ public class SshDaemon extends SshServer implements SshInfo, LifecycleListener {
 | 
				
			|||||||
    setKeyPairProvider(hostKeyProvider);
 | 
					    setKeyPairProvider(hostKeyProvider);
 | 
				
			||||||
    setCommandFactory(commandFactory);
 | 
					    setCommandFactory(commandFactory);
 | 
				
			||||||
    setShellFactory(noShell);
 | 
					    setShellFactory(noShell);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    final AtomicInteger connected = new AtomicInteger();
 | 
				
			||||||
 | 
					    metricMaker.newCallbackMetric(
 | 
				
			||||||
 | 
					        "sshd/sessions/connected",
 | 
				
			||||||
 | 
					        Integer.class,
 | 
				
			||||||
 | 
					        new Description("Currently connected SSH sessions")
 | 
				
			||||||
 | 
					          .setGauge()
 | 
				
			||||||
 | 
					          .setUnit("sessions"),
 | 
				
			||||||
 | 
					        new Supplier<Integer>() {
 | 
				
			||||||
 | 
					          @Override
 | 
				
			||||||
 | 
					          public Integer get() {
 | 
				
			||||||
 | 
					            return connected.get();
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    final Counter sesssionsCreated = metricMaker.newCounter(
 | 
				
			||||||
 | 
					        "sshd/sessions/created",
 | 
				
			||||||
 | 
					        new Description("Rate of new SSH sessions")
 | 
				
			||||||
 | 
					          .setRate()
 | 
				
			||||||
 | 
					          .setUnit("sessions"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    setSessionFactory(new SessionFactory() {
 | 
					    setSessionFactory(new SessionFactory() {
 | 
				
			||||||
      @Override
 | 
					      @Override
 | 
				
			||||||
      protected AbstractSession createSession(final IoSession io)
 | 
					      protected AbstractSession createSession(final IoSession io)
 | 
				
			||||||
          throws Exception {
 | 
					          throws Exception {
 | 
				
			||||||
 | 
					        connected.incrementAndGet();
 | 
				
			||||||
 | 
					        sesssionsCreated.increment();
 | 
				
			||||||
        if (io instanceof MinaSession) {
 | 
					        if (io instanceof MinaSession) {
 | 
				
			||||||
          if (((MinaSession) io).getSession()
 | 
					          if (((MinaSession) io).getSession()
 | 
				
			||||||
              .getConfig() instanceof SocketSessionConfig) {
 | 
					              .getConfig() instanceof SocketSessionConfig) {
 | 
				
			||||||
@@ -269,6 +298,7 @@ public class SshDaemon extends SshServer implements SshInfo, LifecycleListener {
 | 
				
			|||||||
        s.addCloseSessionListener(new SshFutureListener<CloseFuture>() {
 | 
					        s.addCloseSessionListener(new SshFutureListener<CloseFuture>() {
 | 
				
			||||||
          @Override
 | 
					          @Override
 | 
				
			||||||
          public void operationComplete(CloseFuture future) {
 | 
					          public void operationComplete(CloseFuture future) {
 | 
				
			||||||
 | 
					            connected.decrementAndGet();
 | 
				
			||||||
            if (sd.isAuthenticationError()) {
 | 
					            if (sd.isAuthenticationError()) {
 | 
				
			||||||
              sshLog.onAuthFail(sd);
 | 
					              sshLog.onAuthFail(sd);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,6 +20,7 @@ import com.google.gerrit.reviewdb.server.ReviewDb;
 | 
				
			|||||||
import com.google.gerrit.server.git.ChangeCache;
 | 
					import com.google.gerrit.server.git.ChangeCache;
 | 
				
			||||||
import com.google.gerrit.server.git.TagCache;
 | 
					import com.google.gerrit.server.git.TagCache;
 | 
				
			||||||
import com.google.gerrit.server.git.TransferConfig;
 | 
					import com.google.gerrit.server.git.TransferConfig;
 | 
				
			||||||
 | 
					import com.google.gerrit.server.git.UploadPackMetricsHook;
 | 
				
			||||||
import com.google.gerrit.server.git.VisibleRefFilter;
 | 
					import com.google.gerrit.server.git.VisibleRefFilter;
 | 
				
			||||||
import com.google.gerrit.server.git.validators.UploadValidationException;
 | 
					import com.google.gerrit.server.git.validators.UploadValidationException;
 | 
				
			||||||
import com.google.gerrit.server.git.validators.UploadValidators;
 | 
					import com.google.gerrit.server.git.validators.UploadValidators;
 | 
				
			||||||
@@ -58,6 +59,9 @@ final class Upload extends AbstractGitCommand {
 | 
				
			|||||||
  @Inject
 | 
					  @Inject
 | 
				
			||||||
  private SshSession session;
 | 
					  private SshSession session;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Inject
 | 
				
			||||||
 | 
					  private UploadPackMetricsHook uploadMetrics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @Override
 | 
					  @Override
 | 
				
			||||||
  protected void runImpl() throws IOException, Failure {
 | 
					  protected void runImpl() throws IOException, Failure {
 | 
				
			||||||
    if (!projectControl.canRunUploadPack()) {
 | 
					    if (!projectControl.canRunUploadPack()) {
 | 
				
			||||||
@@ -71,6 +75,7 @@ final class Upload extends AbstractGitCommand {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    up.setPackConfig(config.getPackConfig());
 | 
					    up.setPackConfig(config.getPackConfig());
 | 
				
			||||||
    up.setTimeout(config.getTimeout());
 | 
					    up.setTimeout(config.getTimeout());
 | 
				
			||||||
 | 
					    up.setPostUploadHook(uploadMetrics);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    List<PreUploadHook> allPreUploadHooks = Lists.newArrayList(preUploadHooks);
 | 
					    List<PreUploadHook> allPreUploadHooks = Lists.newArrayList(preUploadHooks);
 | 
				
			||||||
    allPreUploadHooks.add(uploadValidatorsFactory.create(project, repo,
 | 
					    allPreUploadHooks.add(uploadValidatorsFactory.create(project, repo,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,6 +26,7 @@ import com.google.gerrit.httpd.plugins.HttpPluginModule;
 | 
				
			|||||||
import com.google.gerrit.lifecycle.LifecycleManager;
 | 
					import com.google.gerrit.lifecycle.LifecycleManager;
 | 
				
			||||||
import com.google.gerrit.lifecycle.LifecycleModule;
 | 
					import com.google.gerrit.lifecycle.LifecycleModule;
 | 
				
			||||||
import com.google.gerrit.lucene.LuceneIndexModule;
 | 
					import com.google.gerrit.lucene.LuceneIndexModule;
 | 
				
			||||||
 | 
					import com.google.gerrit.metrics.dropwizard.DropWizardMetricMaker;
 | 
				
			||||||
import com.google.gerrit.reviewdb.client.AuthType;
 | 
					import com.google.gerrit.reviewdb.client.AuthType;
 | 
				
			||||||
import com.google.gerrit.server.account.InternalAccountDirectory;
 | 
					import com.google.gerrit.server.account.InternalAccountDirectory;
 | 
				
			||||||
import com.google.gerrit.server.cache.h2.DefaultCacheFactory;
 | 
					import com.google.gerrit.server.cache.h2.DefaultCacheFactory;
 | 
				
			||||||
@@ -288,6 +289,7 @@ public class WebAppInitializer extends GuiceServletContextListener
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  private Injector createSysInjector() {
 | 
					  private Injector createSysInjector() {
 | 
				
			||||||
    final List<Module> modules = new ArrayList<>();
 | 
					    final List<Module> modules = new ArrayList<>();
 | 
				
			||||||
 | 
					    modules.add(new DropWizardMetricMaker.Module());
 | 
				
			||||||
    modules.add(new WorkQueue.Module());
 | 
					    modules.add(new WorkQueue.Module());
 | 
				
			||||||
    modules.add(new ChangeHookRunner.Module());
 | 
					    modules.add(new ChangeHookRunner.Module());
 | 
				
			||||||
    modules.add(new ReceiveCommitsExecutorModule());
 | 
					    modules.add(new ReceiveCommitsExecutorModule());
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										8
									
								
								lib/dropwizard/BUCK
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								lib/dropwizard/BUCK
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					include_defs('//lib/maven.defs')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					maven_jar(
 | 
				
			||||||
 | 
					  name = 'dropwizard-core',
 | 
				
			||||||
 | 
					  id = 'io.dropwizard.metrics:metrics-core:3.1.2',
 | 
				
			||||||
 | 
					  sha1 = '224f03afd2521c6c94632f566beb1bb5ee32cf07',
 | 
				
			||||||
 | 
					  license = 'Apache2.0',
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
		Reference in New Issue
	
	Block a user