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:
parent
40d64f6d43
commit
f70a242ad5
@ -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',
|
||||||
|
)
|
Loading…
Reference in New Issue
Block a user