Extract metrics package from gerrit-server top-level directory
Change-Id: I7c21b82de289ebc24b530d6b37abf6c33b4dec2f
This commit is contained in:

committed by
Dave Borowitz

parent
bd3f50e61b
commit
1f78f3efa1
15
java/com/google/gerrit/metrics/BUILD
Normal file
15
java/com/google/gerrit/metrics/BUILD
Normal file
@@ -0,0 +1,15 @@
|
||||
java_library(
|
||||
name = "metrics",
|
||||
srcs = glob(["**/*.java"]),
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//java/com/google/gerrit/common:server",
|
||||
"//java/com/google/gerrit/extensions:api",
|
||||
"//java/com/google/gerrit/lifecycle",
|
||||
"//java/org/eclipse/jgit:server",
|
||||
"//lib:guava",
|
||||
"//lib/guice",
|
||||
"//lib/jgit/org.eclipse.jgit:jgit",
|
||||
"//lib/log:api",
|
||||
],
|
||||
)
|
27
java/com/google/gerrit/metrics/CallbackMetric.java
Normal file
27
java/com/google/gerrit/metrics/CallbackMetric.java
Normal file
@@ -0,0 +1,27 @@
|
||||
// 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.
|
||||
*
|
||||
* @see CallbackMetric0
|
||||
* @param <V> type of the metric value, typically Integer or Long.
|
||||
*/
|
||||
public interface CallbackMetric<V> extends RegistrationHandle {
|
||||
void prune();
|
||||
}
|
43
java/com/google/gerrit/metrics/CallbackMetric0.java
Normal file
43
java/com/google/gerrit/metrics/CallbackMetric0.java
Normal file
@@ -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;
|
||||
|
||||
/**
|
||||
* Metric whose value is supplied when the trigger is invoked.
|
||||
*
|
||||
* <pre>
|
||||
* CallbackMetric0<Long> hits = metricMaker.newCallbackMetric("hits", ...);
|
||||
* CallbackMetric0<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 CallbackMetric0<V> implements CallbackMetric<V> {
|
||||
/**
|
||||
* Supply the current value of the metric.
|
||||
*
|
||||
* @param value current value.
|
||||
*/
|
||||
public abstract void set(V value);
|
||||
|
||||
@Override
|
||||
public void prune() {}
|
||||
}
|
42
java/com/google/gerrit/metrics/CallbackMetric1.java
Normal file
42
java/com/google/gerrit/metrics/CallbackMetric1.java
Normal file
@@ -0,0 +1,42 @@
|
||||
// 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;
|
||||
|
||||
/**
|
||||
* Metric whose value is supplied when the trigger is invoked.
|
||||
*
|
||||
* @param <F1> type of the field.
|
||||
* @param <V> type of the metric value, typically Integer or Long.
|
||||
*/
|
||||
public abstract class CallbackMetric1<F1, V> implements CallbackMetric<V> {
|
||||
/**
|
||||
* Supply the current value of the metric.
|
||||
*
|
||||
* @param field1 bucket to increment.
|
||||
* @param value current value.
|
||||
*/
|
||||
public abstract void set(F1 field1, V value);
|
||||
|
||||
/**
|
||||
* Ensure a zeroed metric is created for the field value.
|
||||
*
|
||||
* @param field1 bucket to create.
|
||||
*/
|
||||
public abstract void forceCreate(F1 field1);
|
||||
|
||||
/** Prune any submetrics that were not assigned during this trigger. */
|
||||
@Override
|
||||
public void prune() {}
|
||||
}
|
41
java/com/google/gerrit/metrics/Counter0.java
Normal file
41
java/com/google/gerrit/metrics/Counter0.java
Normal file
@@ -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 Counter0 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);
|
||||
}
|
48
java/com/google/gerrit/metrics/Counter1.java
Normal file
48
java/com/google/gerrit/metrics/Counter1.java
Normal file
@@ -0,0 +1,48 @@
|
||||
// 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}.
|
||||
*
|
||||
* @param <F1> type of the field.
|
||||
*/
|
||||
public abstract class Counter1<F1> implements RegistrationHandle {
|
||||
/**
|
||||
* Increment the counter by one event.
|
||||
*
|
||||
* @param field1 bucket to increment.
|
||||
*/
|
||||
public void increment(F1 field1) {
|
||||
incrementBy(field1, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment the counter by a specified amount.
|
||||
*
|
||||
* @param field1 bucket to increment.
|
||||
* @param value value to increment by, must be >= 0.
|
||||
*/
|
||||
public abstract void incrementBy(F1 field1, long value);
|
||||
}
|
51
java/com/google/gerrit/metrics/Counter2.java
Normal file
51
java/com/google/gerrit/metrics/Counter2.java
Normal file
@@ -0,0 +1,51 @@
|
||||
// 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}.
|
||||
*
|
||||
* @param <F1> type of the field.
|
||||
* @param <F2> type of the field.
|
||||
*/
|
||||
public abstract class Counter2<F1, F2> implements RegistrationHandle {
|
||||
/**
|
||||
* Increment the counter by one event.
|
||||
*
|
||||
* @param field1 bucket to increment.
|
||||
* @param field2 bucket to increment.
|
||||
*/
|
||||
public void increment(F1 field1, F2 field2) {
|
||||
incrementBy(field1, field2, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment the counter by a specified amount.
|
||||
*
|
||||
* @param field1 bucket to increment.
|
||||
* @param field2 bucket to increment.
|
||||
* @param value value to increment by, must be >= 0.
|
||||
*/
|
||||
public abstract void incrementBy(F1 field1, F2 field2, long value);
|
||||
}
|
54
java/com/google/gerrit/metrics/Counter3.java
Normal file
54
java/com/google/gerrit/metrics/Counter3.java
Normal file
@@ -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 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}.
|
||||
*
|
||||
* @param <F1> type of the field.
|
||||
* @param <F2> type of the field.
|
||||
* @param <F3> type of the field.
|
||||
*/
|
||||
public abstract class Counter3<F1, F2, F3> implements RegistrationHandle {
|
||||
/**
|
||||
* Increment the counter by one event.
|
||||
*
|
||||
* @param field1 bucket to increment.
|
||||
* @param field2 bucket to increment.
|
||||
* @param field3 bucket to increment.
|
||||
*/
|
||||
public void increment(F1 field1, F2 field2, F3 field3) {
|
||||
incrementBy(field1, field2, field3, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment the counter by a specified amount.
|
||||
*
|
||||
* @param field1 bucket to increment.
|
||||
* @param field2 bucket to increment.
|
||||
* @param field3 bucket to increment.
|
||||
* @param value value to increment by, must be >= 0.
|
||||
*/
|
||||
public abstract void incrementBy(F1 field1, F2 field2, F3 field3, long value);
|
||||
}
|
199
java/com/google/gerrit/metrics/Description.java
Normal file
199
java/com/google/gerrit/metrics/Description.java
Normal file
@@ -0,0 +1,199 @@
|
||||
// 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.Strings;
|
||||
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 CONSTANT = "CONSTANT";
|
||||
public static final String FIELD_ORDERING = "FIELD_ORDERING";
|
||||
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() {}
|
||||
}
|
||||
|
||||
public enum FieldOrdering {
|
||||
/** Default ordering places fields at end of the parent metric name. */
|
||||
AT_END,
|
||||
|
||||
/**
|
||||
* Splits the metric name by inserting field values before the last '/' in the metric name. For
|
||||
* example {@code "plugins/replication/push_latency"} with a {@code Field.ofString("remote")}
|
||||
* will create submetrics named {@code "plugins/replication/some-server/push_latency"}.
|
||||
*/
|
||||
PREFIX_FIELDS_BASENAME;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set unit used to describe the value.
|
||||
*
|
||||
* @param unitName name of the unit, e.g. "requests", "seconds", etc.
|
||||
* @return this
|
||||
*/
|
||||
public Description setUnit(String unitName) {
|
||||
annotations.put(UNIT, unitName);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the value as constant for the life of this process. Typically used for software versions,
|
||||
* command line arguments, etc. that cannot change without a process restart.
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
public Description setConstant() {
|
||||
annotations.put(CONSTANT, TRUE_VALUE);
|
||||
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 Counter0}.
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
public Description setGauge() {
|
||||
annotations.put(GAUGE, TRUE_VALUE);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates the metric accumulates over the lifespan of the process. A {@link Counter0} like
|
||||
* total requests handled accumulates over the process and should be {@code setCumulative()}.
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
public Description setCumulative() {
|
||||
annotations.put(CUMULATIVE, TRUE_VALUE);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure how fields are ordered into submetric names.
|
||||
*
|
||||
* @param ordering field ordering
|
||||
* @return this
|
||||
*/
|
||||
public Description setFieldOrdering(FieldOrdering ordering) {
|
||||
annotations.put(FIELD_ORDERING, ordering.name());
|
||||
return this;
|
||||
}
|
||||
|
||||
/** @return true if the metric value never changes after startup. */
|
||||
public boolean isConstant() {
|
||||
return TRUE_VALUE.equals(annotations.get(CONSTANT));
|
||||
}
|
||||
|
||||
/** @return true if the metric may be interpreted as a rate over time. */
|
||||
public boolean isRate() {
|
||||
return TRUE_VALUE.equals(annotations.get(RATE));
|
||||
}
|
||||
|
||||
/** @return true if the metric is an instantaneous sample. */
|
||||
public boolean isGauge() {
|
||||
return TRUE_VALUE.equals(annotations.get(GAUGE));
|
||||
}
|
||||
|
||||
/** @return true if the metric accumulates over the lifespan of the process. */
|
||||
public boolean isCumulative() {
|
||||
return TRUE_VALUE.equals(annotations.get(CUMULATIVE));
|
||||
}
|
||||
|
||||
/** @return the suggested field ordering. */
|
||||
public FieldOrdering getFieldOrdering() {
|
||||
String o = annotations.get(FIELD_ORDERING);
|
||||
return o != null ? FieldOrdering.valueOf(o) : FieldOrdering.AT_END;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode the unit as a unit of time.
|
||||
*
|
||||
* @return valid time unit.
|
||||
* @throws IllegalArgumentException if the unit is not a valid unit of time.
|
||||
*/
|
||||
public TimeUnit getTimeUnit() {
|
||||
return getTimeUnit(annotations.get(UNIT));
|
||||
}
|
||||
|
||||
private static final ImmutableMap<String, TimeUnit> TIME_UNITS =
|
||||
ImmutableMap.of(
|
||||
Units.NANOSECONDS, TimeUnit.NANOSECONDS,
|
||||
Units.MICROSECONDS, TimeUnit.MICROSECONDS,
|
||||
Units.MILLISECONDS, TimeUnit.MILLISECONDS,
|
||||
Units.SECONDS, TimeUnit.SECONDS);
|
||||
|
||||
public static TimeUnit getTimeUnit(String unit) {
|
||||
if (Strings.isNullOrEmpty(unit)) {
|
||||
throw new IllegalArgumentException("no unit configured");
|
||||
}
|
||||
TimeUnit u = TIME_UNITS.get(unit);
|
||||
if (u == null) {
|
||||
throw new IllegalArgumentException(String.format("unit %s not TimeUnit", unit));
|
||||
}
|
||||
return u;
|
||||
}
|
||||
|
||||
/** @return immutable copy of all annotations (configurable properties). */
|
||||
public ImmutableMap<String, String> getAnnotations() {
|
||||
return ImmutableMap.copyOf(annotations);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return annotations.toString();
|
||||
}
|
||||
}
|
195
java/com/google/gerrit/metrics/DisabledMetricMaker.java
Normal file
195
java/com/google/gerrit/metrics/DisabledMetricMaker.java
Normal file
@@ -0,0 +1,195 @@
|
||||
// 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;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/** Exports no metrics, useful for running batch programs. */
|
||||
public class DisabledMetricMaker extends MetricMaker {
|
||||
@Override
|
||||
public Counter0 newCounter(String name, Description desc) {
|
||||
return new Counter0() {
|
||||
@Override
|
||||
public void incrementBy(long value) {}
|
||||
|
||||
@Override
|
||||
public void remove() {}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public <F1> Counter1<F1> newCounter(String name, Description desc, Field<F1> field1) {
|
||||
return new Counter1<F1>() {
|
||||
@Override
|
||||
public void incrementBy(F1 field1, long value) {}
|
||||
|
||||
@Override
|
||||
public void remove() {}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public <F1, F2> Counter2<F1, F2> newCounter(
|
||||
String name, Description desc, Field<F1> field1, Field<F2> field2) {
|
||||
return new Counter2<F1, F2>() {
|
||||
@Override
|
||||
public void incrementBy(F1 field1, F2 field2, long value) {}
|
||||
|
||||
@Override
|
||||
public void remove() {}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public <F1, F2, F3> Counter3<F1, F2, F3> newCounter(
|
||||
String name, Description desc, Field<F1> field1, Field<F2> field2, Field<F3> field3) {
|
||||
return new Counter3<F1, F2, F3>() {
|
||||
@Override
|
||||
public void incrementBy(F1 field1, F2 field2, F3 field3, long value) {}
|
||||
|
||||
@Override
|
||||
public void remove() {}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Timer0 newTimer(String name, Description desc) {
|
||||
return new Timer0() {
|
||||
@Override
|
||||
public void record(long value, TimeUnit unit) {}
|
||||
|
||||
@Override
|
||||
public void remove() {}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public <F1> Timer1<F1> newTimer(String name, Description desc, Field<F1> field1) {
|
||||
return new Timer1<F1>() {
|
||||
@Override
|
||||
public void record(F1 field1, long value, TimeUnit unit) {}
|
||||
|
||||
@Override
|
||||
public void remove() {}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public <F1, F2> Timer2<F1, F2> newTimer(
|
||||
String name, Description desc, Field<F1> field1, Field<F2> field2) {
|
||||
return new Timer2<F1, F2>() {
|
||||
@Override
|
||||
public void record(F1 field1, F2 field2, long value, TimeUnit unit) {}
|
||||
|
||||
@Override
|
||||
public void remove() {}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public <F1, F2, F3> Timer3<F1, F2, F3> newTimer(
|
||||
String name, Description desc, Field<F1> field1, Field<F2> field2, Field<F3> field3) {
|
||||
return new Timer3<F1, F2, F3>() {
|
||||
@Override
|
||||
public void record(F1 field1, F2 field2, F3 field3, long value, TimeUnit unit) {}
|
||||
|
||||
@Override
|
||||
public void remove() {}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Histogram0 newHistogram(String name, Description desc) {
|
||||
return new Histogram0() {
|
||||
@Override
|
||||
public void record(long value) {}
|
||||
|
||||
@Override
|
||||
public void remove() {}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public <F1> Histogram1<F1> newHistogram(String name, Description desc, Field<F1> field1) {
|
||||
return new Histogram1<F1>() {
|
||||
@Override
|
||||
public void record(F1 field1, long value) {}
|
||||
|
||||
@Override
|
||||
public void remove() {}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public <F1, F2> Histogram2<F1, F2> newHistogram(
|
||||
String name, Description desc, Field<F1> field1, Field<F2> field2) {
|
||||
return new Histogram2<F1, F2>() {
|
||||
@Override
|
||||
public void record(F1 field1, F2 field2, long value) {}
|
||||
|
||||
@Override
|
||||
public void remove() {}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public <F1, F2, F3> Histogram3<F1, F2, F3> newHistogram(
|
||||
String name, Description desc, Field<F1> field1, Field<F2> field2, Field<F3> field3) {
|
||||
return new Histogram3<F1, F2, F3>() {
|
||||
@Override
|
||||
public void record(F1 field1, F2 field2, F3 field3, long value) {}
|
||||
|
||||
@Override
|
||||
public void remove() {}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V> CallbackMetric0<V> newCallbackMetric(
|
||||
String name, Class<V> valueClass, Description desc) {
|
||||
return new CallbackMetric0<V>() {
|
||||
@Override
|
||||
public void set(V value) {}
|
||||
|
||||
@Override
|
||||
public void remove() {}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public <F1, V> CallbackMetric1<F1, V> newCallbackMetric(
|
||||
String name, Class<V> valueClass, Description desc, Field<F1> field1) {
|
||||
return new CallbackMetric1<F1, V>() {
|
||||
@Override
|
||||
public void set(F1 field1, V value) {}
|
||||
|
||||
@Override
|
||||
public void forceCreate(F1 field1) {}
|
||||
|
||||
@Override
|
||||
public void remove() {}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegistrationHandle newTrigger(Set<CallbackMetric<?>> metrics, Runnable trigger) {
|
||||
return new RegistrationHandle() {
|
||||
@Override
|
||||
public void remove() {}
|
||||
};
|
||||
}
|
||||
}
|
170
java/com/google/gerrit/metrics/Field.java
Normal file
170
java/com/google/gerrit/metrics/Field.java
Normal file
@@ -0,0 +1,170 @@
|
||||
// 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 com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Functions;
|
||||
|
||||
/**
|
||||
* Describes a bucketing field used by a metric.
|
||||
*
|
||||
* @param <T> type of field
|
||||
*/
|
||||
public class Field<T> {
|
||||
/**
|
||||
* Break down metrics by boolean true/false.
|
||||
*
|
||||
* @param name field name
|
||||
* @return boolean field
|
||||
*/
|
||||
public static Field<Boolean> ofBoolean(String name) {
|
||||
return ofBoolean(name, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Break down metrics by boolean true/false.
|
||||
*
|
||||
* @param name field name
|
||||
* @param description field description
|
||||
* @return boolean field
|
||||
*/
|
||||
public static Field<Boolean> ofBoolean(String name, String description) {
|
||||
return new Field<>(name, Boolean.class, description);
|
||||
}
|
||||
|
||||
/**
|
||||
* Break down metrics by cases of an enum.
|
||||
*
|
||||
* @param enumType type of enum
|
||||
* @param name field name
|
||||
* @return enum field
|
||||
*/
|
||||
public static <E extends Enum<E>> Field<E> ofEnum(Class<E> enumType, String name) {
|
||||
return ofEnum(enumType, name, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Break down metrics by cases of an enum.
|
||||
*
|
||||
* @param enumType type of enum
|
||||
* @param name field name
|
||||
* @param description field description
|
||||
* @return enum field
|
||||
*/
|
||||
public static <E extends Enum<E>> Field<E> ofEnum(
|
||||
Class<E> enumType, String name, String description) {
|
||||
return new Field<>(name, enumType, description);
|
||||
}
|
||||
|
||||
/**
|
||||
* Break down metrics by string.
|
||||
*
|
||||
* <p>Each unique string will allocate a new submetric. <b>Do not use user content as a field
|
||||
* value</b> as field values are never reclaimed.
|
||||
*
|
||||
* @param name field name
|
||||
* @return string field
|
||||
*/
|
||||
public static Field<String> ofString(String name) {
|
||||
return ofString(name, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Break down metrics by string.
|
||||
*
|
||||
* <p>Each unique string will allocate a new submetric. <b>Do not use user content as a field
|
||||
* value</b> as field values are never reclaimed.
|
||||
*
|
||||
* @param name field name
|
||||
* @param description field description
|
||||
* @return string field
|
||||
*/
|
||||
public static Field<String> ofString(String name, String description) {
|
||||
return new Field<>(name, String.class, description);
|
||||
}
|
||||
|
||||
/**
|
||||
* Break down metrics by integer.
|
||||
*
|
||||
* <p>Each unique integer will allocate a new submetric. <b>Do not use user content as a field
|
||||
* value</b> as field values are never reclaimed.
|
||||
*
|
||||
* @param name field name
|
||||
* @return integer field
|
||||
*/
|
||||
public static Field<Integer> ofInteger(String name) {
|
||||
return ofInteger(name, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Break down metrics by integer.
|
||||
*
|
||||
* <p>Each unique integer will allocate a new submetric. <b>Do not use user content as a field
|
||||
* value</b> as field values are never reclaimed.
|
||||
*
|
||||
* @param name field name
|
||||
* @param description field description
|
||||
* @return integer field
|
||||
*/
|
||||
public static Field<Integer> ofInteger(String name, String description) {
|
||||
return new Field<>(name, Integer.class, description);
|
||||
}
|
||||
|
||||
private final String name;
|
||||
private final Class<T> keyType;
|
||||
private final Function<T, String> formatter;
|
||||
private final String description;
|
||||
|
||||
private Field(String name, Class<T> keyType, String description) {
|
||||
checkArgument(name.matches("^[a-z_]+$"), "name must match [a-z_]");
|
||||
this.name = name;
|
||||
this.keyType = keyType;
|
||||
this.formatter = initFormatter(keyType);
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
/** @return name of this field within the metric. */
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/** @return type of value used within the field. */
|
||||
public Class<T> getType() {
|
||||
return keyType;
|
||||
}
|
||||
|
||||
/** @return description text for the field explaining its range of values. */
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public Function<T, String> formatter() {
|
||||
return formatter;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T> Function<T, String> initFormatter(Class<T> keyType) {
|
||||
if (keyType == String.class) {
|
||||
return (Function<T, String>) Functions.<String>identity();
|
||||
} else if (keyType == Integer.class || keyType == Boolean.class) {
|
||||
return (Function<T, String>) Functions.toStringFunction();
|
||||
} else if (Enum.class.isAssignableFrom(keyType)) {
|
||||
return in -> ((Enum<?>) in).name();
|
||||
}
|
||||
throw new IllegalStateException("unsupported type " + keyType.getName());
|
||||
}
|
||||
}
|
31
java/com/google/gerrit/metrics/Histogram0.java
Normal file
31
java/com/google/gerrit/metrics/Histogram0.java
Normal file
@@ -0,0 +1,31 @@
|
||||
// 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;
|
||||
|
||||
/**
|
||||
* Measures the statistical distribution of values in a stream of data.
|
||||
*
|
||||
* <p>Suitable uses are "response size in bytes", etc.
|
||||
*/
|
||||
public abstract class Histogram0 implements RegistrationHandle {
|
||||
/**
|
||||
* Record a sample of a specified amount.
|
||||
*
|
||||
* @param value to record
|
||||
*/
|
||||
public abstract void record(long value);
|
||||
}
|
34
java/com/google/gerrit/metrics/Histogram1.java
Normal file
34
java/com/google/gerrit/metrics/Histogram1.java
Normal file
@@ -0,0 +1,34 @@
|
||||
// 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;
|
||||
|
||||
/**
|
||||
* Measures the statistical distribution of values in a stream of data.
|
||||
*
|
||||
* <p>Suitable uses are "response size in bytes", etc.
|
||||
*
|
||||
* @param <F1> type of the field.
|
||||
*/
|
||||
public abstract class Histogram1<F1> implements RegistrationHandle {
|
||||
/**
|
||||
* Record a sample of a specified amount.
|
||||
*
|
||||
* @param field1 bucket to record sample
|
||||
* @param value value to record
|
||||
*/
|
||||
public abstract void record(F1 field1, long value);
|
||||
}
|
36
java/com/google/gerrit/metrics/Histogram2.java
Normal file
36
java/com/google/gerrit/metrics/Histogram2.java
Normal file
@@ -0,0 +1,36 @@
|
||||
// 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;
|
||||
|
||||
/**
|
||||
* Measures the statistical distribution of values in a stream of data.
|
||||
*
|
||||
* <p>Suitable uses are "response size in bytes", etc.
|
||||
*
|
||||
* @param <F1> type of the field.
|
||||
* @param <F2> type of the field.
|
||||
*/
|
||||
public abstract class Histogram2<F1, F2> implements RegistrationHandle {
|
||||
/**
|
||||
* Record a sample of a specified amount.
|
||||
*
|
||||
* @param field1 bucket to record sample
|
||||
* @param field2 bucket to record sample
|
||||
* @param value value to record
|
||||
*/
|
||||
public abstract void record(F1 field1, F2 field2, long value);
|
||||
}
|
38
java/com/google/gerrit/metrics/Histogram3.java
Normal file
38
java/com/google/gerrit/metrics/Histogram3.java
Normal file
@@ -0,0 +1,38 @@
|
||||
// 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;
|
||||
|
||||
/**
|
||||
* Measures the statistical distribution of values in a stream of data.
|
||||
*
|
||||
* <p>Suitable uses are "response size in bytes", etc.
|
||||
*
|
||||
* @param <F1> type of the field.
|
||||
* @param <F2> type of the field.
|
||||
* @param <F3> type of the field.
|
||||
*/
|
||||
public abstract class Histogram3<F1, F2, F3> implements RegistrationHandle {
|
||||
/**
|
||||
* Record a sample of a specified amount.
|
||||
*
|
||||
* @param field1 bucket to record sample
|
||||
* @param field2 bucket to record sample
|
||||
* @param field3 bucket to record sample
|
||||
* @param value value to record
|
||||
*/
|
||||
public abstract void record(F1 field1, F2 field2, F3 field3, long value);
|
||||
}
|
156
java/com/google/gerrit/metrics/MetricMaker.java
Normal file
156
java/com/google/gerrit/metrics/MetricMaker.java
Normal file
@@ -0,0 +1,156 @@
|
||||
// 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.
|
||||
*
|
||||
* @param name field name
|
||||
* @param desc field description
|
||||
* @return counter
|
||||
*/
|
||||
public abstract Counter0 newCounter(String name, Description desc);
|
||||
|
||||
public abstract <F1> Counter1<F1> newCounter(String name, Description desc, Field<F1> field1);
|
||||
|
||||
public abstract <F1, F2> Counter2<F1, F2> newCounter(
|
||||
String name, Description desc, Field<F1> field1, Field<F2> field2);
|
||||
|
||||
public abstract <F1, F2, F3> Counter3<F1, F2, F3> newCounter(
|
||||
String name, Description desc, Field<F1> field1, Field<F2> field2, Field<F3> field3);
|
||||
|
||||
/**
|
||||
* Metric recording time spent on an operation.
|
||||
*
|
||||
* @param name field name
|
||||
* @param desc field description
|
||||
* @return timer
|
||||
*/
|
||||
public abstract Timer0 newTimer(String name, Description desc);
|
||||
|
||||
public abstract <F1> Timer1<F1> newTimer(String name, Description desc, Field<F1> field1);
|
||||
|
||||
public abstract <F1, F2> Timer2<F1, F2> newTimer(
|
||||
String name, Description desc, Field<F1> field1, Field<F2> field2);
|
||||
|
||||
public abstract <F1, F2, F3> Timer3<F1, F2, F3> newTimer(
|
||||
String name, Description desc, Field<F1> field1, Field<F2> field2, Field<F3> field3);
|
||||
|
||||
/**
|
||||
* Metric recording statistical distribution of values.
|
||||
*
|
||||
* @param name field name
|
||||
* @param desc field description
|
||||
* @return histogram
|
||||
*/
|
||||
public abstract Histogram0 newHistogram(String name, Description desc);
|
||||
|
||||
public abstract <F1> Histogram1<F1> newHistogram(String name, Description desc, Field<F1> field1);
|
||||
|
||||
public abstract <F1, F2> Histogram2<F1, F2> newHistogram(
|
||||
String name, Description desc, Field<F1> field1, Field<F2> field2);
|
||||
|
||||
public abstract <F1, F2, F3> Histogram3<F1, F2, F3> newHistogram(
|
||||
String name, Description desc, Field<F1> field1, Field<F2> field2, Field<F3> field3);
|
||||
|
||||
/**
|
||||
* Constant value that does not change.
|
||||
*
|
||||
* @param name unique name of the metric.
|
||||
* @param value only value of the metric.
|
||||
* @param desc description of the metric.
|
||||
*/
|
||||
public <V> void newConstantMetric(String name, V value, Description desc) {
|
||||
desc.setConstant();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<V> type = (Class<V>) value.getClass();
|
||||
CallbackMetric0<V> metric = newCallbackMetric(name, type, desc);
|
||||
newTrigger(metric, () -> metric.set(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, Supplier<V> trigger) {
|
||||
CallbackMetric0<V> metric = newCallbackMetric(name, valueClass, desc);
|
||||
newTrigger(metric, () -> metric.set(trigger.get()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantaneous reading of a single value.
|
||||
*
|
||||
* @param name field name
|
||||
* @param valueClass field type
|
||||
* @param desc field description
|
||||
* @return callback
|
||||
*/
|
||||
public abstract <V> CallbackMetric0<V> newCallbackMetric(
|
||||
String name, Class<V> valueClass, Description desc);
|
||||
|
||||
public abstract <F1, V> CallbackMetric1<F1, V> newCallbackMetric(
|
||||
String name, Class<V> valueClass, Description desc, Field<F1> field1);
|
||||
|
||||
/**
|
||||
* Connect logic to populate a previously created {@link CallbackMetric}.
|
||||
*
|
||||
* @param metric1 previously created callback
|
||||
* @param trigger trigger to connect
|
||||
* @return registration handle
|
||||
*/
|
||||
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);
|
||||
}
|
62
java/com/google/gerrit/metrics/Timer0.java
Normal file
62
java/com/google/gerrit/metrics/Timer0.java
Normal file
@@ -0,0 +1,62 @@
|
||||
// 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 (Timer0.Context ctx = timer.start()) {
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
public abstract class Timer0 implements RegistrationHandle {
|
||||
public static class Context extends TimerContext {
|
||||
private final Timer0 timer;
|
||||
|
||||
Context(Timer0 timer) {
|
||||
this.timer = timer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void record(long elapsed) {
|
||||
timer.record(elapsed, NANOSECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin a timer for the current block, value will be recorded when closed.
|
||||
*
|
||||
* @return timer context
|
||||
*/
|
||||
public Context start() {
|
||||
return new Context(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Record a value in the distribution.
|
||||
*
|
||||
* @param value value to record
|
||||
* @param unit time unit of the value
|
||||
*/
|
||||
public abstract void record(long value, TimeUnit unit);
|
||||
}
|
69
java/com/google/gerrit/metrics/Timer1.java
Normal file
69
java/com/google/gerrit/metrics/Timer1.java
Normal file
@@ -0,0 +1,69 @@
|
||||
// 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 (Timer1.Context ctx = timer.start(field)) {
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @param <F1> type of the field.
|
||||
*/
|
||||
public abstract class Timer1<F1> implements RegistrationHandle {
|
||||
public static class Context extends TimerContext {
|
||||
private final Timer1<Object> timer;
|
||||
private final Object field1;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
<F1> Context(Timer1<F1> timer, F1 field1) {
|
||||
this.timer = (Timer1<Object>) timer;
|
||||
this.field1 = field1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void record(long elapsed) {
|
||||
timer.record(field1, elapsed, NANOSECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin a timer for the current block, value will be recorded when closed.
|
||||
*
|
||||
* @param field1 bucket to record the timer
|
||||
* @return timer context
|
||||
*/
|
||||
public Context start(F1 field1) {
|
||||
return new Context(this, field1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Record a value in the distribution.
|
||||
*
|
||||
* @param field1 bucket to record the timer
|
||||
* @param value value to record
|
||||
* @param unit time unit of the value
|
||||
*/
|
||||
public abstract void record(F1 field1, long value, TimeUnit unit);
|
||||
}
|
74
java/com/google/gerrit/metrics/Timer2.java
Normal file
74
java/com/google/gerrit/metrics/Timer2.java
Normal file
@@ -0,0 +1,74 @@
|
||||
// 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 (Timer2.Context ctx = timer.start(field)) {
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @param <F1> type of the field.
|
||||
* @param <F2> type of the field.
|
||||
*/
|
||||
public abstract class Timer2<F1, F2> implements RegistrationHandle {
|
||||
public static class Context extends TimerContext {
|
||||
private final Timer2<Object, Object> timer;
|
||||
private final Object field1;
|
||||
private final Object field2;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
<F1, F2> Context(Timer2<F1, F2> timer, F1 field1, F2 field2) {
|
||||
this.timer = (Timer2<Object, Object>) timer;
|
||||
this.field1 = field1;
|
||||
this.field2 = field2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void record(long elapsed) {
|
||||
timer.record(field1, field2, elapsed, NANOSECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin a timer for the current block, value will be recorded when closed.
|
||||
*
|
||||
* @param field1 bucket to record the timer
|
||||
* @param field2 bucket to record the timer
|
||||
* @return timer context
|
||||
*/
|
||||
public Context start(F1 field1, F2 field2) {
|
||||
return new Context(this, field1, field2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Record a value in the distribution.
|
||||
*
|
||||
* @param field1 bucket to record the timer
|
||||
* @param field2 bucket to record the timer
|
||||
* @param value value to record
|
||||
* @param unit time unit of the value
|
||||
*/
|
||||
public abstract void record(F1 field1, F2 field2, long value, TimeUnit unit);
|
||||
}
|
79
java/com/google/gerrit/metrics/Timer3.java
Normal file
79
java/com/google/gerrit/metrics/Timer3.java
Normal file
@@ -0,0 +1,79 @@
|
||||
// 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 (Timer3.Context ctx = timer.start(field)) {
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @param <F1> type of the field.
|
||||
* @param <F2> type of the field.
|
||||
* @param <F3> type of the field.
|
||||
*/
|
||||
public abstract class Timer3<F1, F2, F3> implements RegistrationHandle {
|
||||
public static class Context extends TimerContext {
|
||||
private final Timer3<Object, Object, Object> timer;
|
||||
private final Object field1;
|
||||
private final Object field2;
|
||||
private final Object field3;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
<F1, F2, F3> Context(Timer3<F1, F2, F3> timer, F1 f1, F2 f2, F3 f3) {
|
||||
this.timer = (Timer3<Object, Object, Object>) timer;
|
||||
this.field1 = f1;
|
||||
this.field2 = f2;
|
||||
this.field3 = f3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void record(long elapsed) {
|
||||
timer.record(field1, field2, field3, elapsed, NANOSECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin a timer for the current block, value will be recorded when closed.
|
||||
*
|
||||
* @param field1 bucket to record the timer
|
||||
* @param field2 bucket to record the timer
|
||||
* @param field3 bucket to record the timer
|
||||
* @return timer context
|
||||
*/
|
||||
public Context start(F1 field1, F2 field2, F3 field3) {
|
||||
return new Context(this, field1, field2, field3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Record a value in the distribution.
|
||||
*
|
||||
* @param field1 bucket to record the timer
|
||||
* @param field2 bucket to record the timer
|
||||
* @param field3 bucket to record the timer
|
||||
* @param value value to record
|
||||
* @param unit time unit of the value
|
||||
*/
|
||||
public abstract void record(F1 field1, F2 field2, F3 field3, long value, TimeUnit unit);
|
||||
}
|
59
java/com/google/gerrit/metrics/TimerContext.java
Normal file
59
java/com/google/gerrit/metrics/TimerContext.java
Normal file
@@ -0,0 +1,59 @@
|
||||
// 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;
|
||||
|
||||
abstract class TimerContext implements AutoCloseable {
|
||||
private final long startNanos;
|
||||
private boolean stopped;
|
||||
|
||||
TimerContext() {
|
||||
this.startNanos = System.nanoTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* Record the elapsed time to the timer.
|
||||
*
|
||||
* @param elapsed Elapsed time in nanoseconds.
|
||||
*/
|
||||
public abstract void record(long elapsed);
|
||||
|
||||
/** @return the start time in system time nanoseconds. */
|
||||
public long getStartTime() {
|
||||
return startNanos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the timer and record the elapsed time.
|
||||
*
|
||||
* @return the elapsed time in nanoseconds.
|
||||
* @throws IllegalStateException if the timer is already stopped.
|
||||
*/
|
||||
public long stop() {
|
||||
if (!stopped) {
|
||||
stopped = true;
|
||||
long elapsed = System.nanoTime() - startNanos;
|
||||
record(elapsed);
|
||||
return elapsed;
|
||||
}
|
||||
throw new IllegalStateException("Already stopped");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (!stopped) {
|
||||
stop();
|
||||
}
|
||||
}
|
||||
}
|
15
java/com/google/gerrit/metrics/dropwizard/BUILD
Normal file
15
java/com/google/gerrit/metrics/dropwizard/BUILD
Normal file
@@ -0,0 +1,15 @@
|
||||
java_library(
|
||||
name = "dropwizard",
|
||||
srcs = glob(["**/*.java"]),
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//gerrit-server:server",
|
||||
"//java/com/google/gerrit/common:annotations",
|
||||
"//java/com/google/gerrit/extensions:api",
|
||||
"//java/com/google/gerrit/metrics",
|
||||
"//lib:args4j",
|
||||
"//lib:guava",
|
||||
"//lib/dropwizard:dropwizard-core",
|
||||
"//lib/guice",
|
||||
],
|
||||
)
|
145
java/com/google/gerrit/metrics/dropwizard/BucketedCallback.java
Normal file
145
java/com/google/gerrit/metrics/dropwizard/BucketedCallback.java
Normal file
@@ -0,0 +1,145 @@
|
||||
// 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 com.codahale.metrics.Gauge;
|
||||
import com.codahale.metrics.Metric;
|
||||
import com.codahale.metrics.MetricRegistry;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.gerrit.metrics.Description;
|
||||
import com.google.gerrit.metrics.Field;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/** Abstract callback metric broken down into buckets. */
|
||||
abstract class BucketedCallback<V> implements BucketedMetric {
|
||||
private final DropWizardMetricMaker metrics;
|
||||
private final MetricRegistry registry;
|
||||
private final String name;
|
||||
private final Description.FieldOrdering ordering;
|
||||
protected final Field<?>[] fields;
|
||||
private final V zero;
|
||||
private final Map<Object, ValueGauge> cells;
|
||||
protected volatile Runnable trigger;
|
||||
private final Object lock = new Object();
|
||||
|
||||
BucketedCallback(
|
||||
DropWizardMetricMaker metrics,
|
||||
MetricRegistry registry,
|
||||
String name,
|
||||
Class<V> valueType,
|
||||
Description desc,
|
||||
Field<?>... fields) {
|
||||
this.metrics = metrics;
|
||||
this.registry = registry;
|
||||
this.name = name;
|
||||
this.ordering = desc.getFieldOrdering();
|
||||
this.fields = fields;
|
||||
this.zero = CallbackMetricImpl0.zeroFor(valueType);
|
||||
this.cells = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
void doRemove() {
|
||||
for (Object key : cells.keySet()) {
|
||||
registry.remove(submetric(key));
|
||||
}
|
||||
metrics.remove(name);
|
||||
}
|
||||
|
||||
void doBeginSet() {
|
||||
for (ValueGauge g : cells.values()) {
|
||||
g.set = false;
|
||||
}
|
||||
}
|
||||
|
||||
void doPrune() {
|
||||
Iterator<Map.Entry<Object, ValueGauge>> i = cells.entrySet().iterator();
|
||||
while (i.hasNext()) {
|
||||
if (!i.next().getValue().set) {
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void doEndSet() {
|
||||
for (ValueGauge g : cells.values()) {
|
||||
if (!g.set) {
|
||||
g.value = zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ValueGauge getOrCreate(Object f1, Object f2) {
|
||||
return getOrCreate(ImmutableList.of(f1, f2));
|
||||
}
|
||||
|
||||
ValueGauge getOrCreate(Object f1, Object f2, Object f3) {
|
||||
return getOrCreate(ImmutableList.of(f1, f2, f3));
|
||||
}
|
||||
|
||||
ValueGauge getOrCreate(Object key) {
|
||||
ValueGauge c = cells.get(key);
|
||||
if (c != null) {
|
||||
return c;
|
||||
}
|
||||
|
||||
synchronized (lock) {
|
||||
c = cells.get(key);
|
||||
if (c == null) {
|
||||
c = new ValueGauge();
|
||||
registry.register(submetric(key), c);
|
||||
cells.put(key, c);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
private String submetric(Object key) {
|
||||
return DropWizardMetricMaker.name(ordering, name, name(key));
|
||||
}
|
||||
|
||||
abstract String name(Object key);
|
||||
|
||||
@Override
|
||||
public Metric getTotal() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Field<?>[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Object, Metric> getCells() {
|
||||
return Maps.transformValues(cells, in -> (Metric) in);
|
||||
}
|
||||
|
||||
final class ValueGauge implements Gauge<V> {
|
||||
volatile V value = zero;
|
||||
boolean set;
|
||||
|
||||
@Override
|
||||
public V getValue() {
|
||||
Runnable t = trigger;
|
||||
if (t != null) {
|
||||
t.run();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
100
java/com/google/gerrit/metrics/dropwizard/BucketedCounter.java
Normal file
100
java/com/google/gerrit/metrics/dropwizard/BucketedCounter.java
Normal file
@@ -0,0 +1,100 @@
|
||||
// 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 com.codahale.metrics.Metric;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.gerrit.metrics.Description;
|
||||
import com.google.gerrit.metrics.Field;
|
||||
import com.google.gerrit.metrics.dropwizard.DropWizardMetricMaker.CounterImpl;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/** Abstract counter broken down into buckets by {@link Field} values. */
|
||||
abstract class BucketedCounter implements BucketedMetric {
|
||||
private final DropWizardMetricMaker metrics;
|
||||
private final String name;
|
||||
private final boolean isRate;
|
||||
private final Description.FieldOrdering ordering;
|
||||
protected final Field<?>[] fields;
|
||||
protected final CounterImpl total;
|
||||
private final Map<Object, CounterImpl> cells;
|
||||
private final Object lock = new Object();
|
||||
|
||||
BucketedCounter(
|
||||
DropWizardMetricMaker metrics, String name, Description desc, Field<?>... fields) {
|
||||
this.metrics = metrics;
|
||||
this.name = name;
|
||||
this.isRate = desc.isRate();
|
||||
this.ordering = desc.getFieldOrdering();
|
||||
this.fields = fields;
|
||||
this.total = metrics.newCounterImpl(name + "_total", isRate);
|
||||
this.cells = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
void doRemove() {
|
||||
for (CounterImpl c : cells.values()) {
|
||||
c.remove();
|
||||
}
|
||||
total.remove();
|
||||
metrics.remove(name);
|
||||
}
|
||||
|
||||
CounterImpl forceCreate(Object f1, Object f2) {
|
||||
return forceCreate(ImmutableList.of(f1, f2));
|
||||
}
|
||||
|
||||
CounterImpl forceCreate(Object f1, Object f2, Object f3) {
|
||||
return forceCreate(ImmutableList.of(f1, f2, f3));
|
||||
}
|
||||
|
||||
CounterImpl forceCreate(Object key) {
|
||||
CounterImpl c = cells.get(key);
|
||||
if (c != null) {
|
||||
return c;
|
||||
}
|
||||
|
||||
synchronized (lock) {
|
||||
c = cells.get(key);
|
||||
if (c == null) {
|
||||
c = metrics.newCounterImpl(submetric(key), isRate);
|
||||
cells.put(key, c);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
private String submetric(Object key) {
|
||||
return DropWizardMetricMaker.name(ordering, name, name(key));
|
||||
}
|
||||
|
||||
abstract String name(Object key);
|
||||
|
||||
@Override
|
||||
public Metric getTotal() {
|
||||
return total.metric;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Field<?>[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Object, Metric> getCells() {
|
||||
return Maps.transformValues(cells, c -> c.metric);
|
||||
}
|
||||
}
|
@@ -0,0 +1,98 @@
|
||||
// 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 com.codahale.metrics.Metric;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.gerrit.metrics.Description;
|
||||
import com.google.gerrit.metrics.Field;
|
||||
import com.google.gerrit.metrics.dropwizard.DropWizardMetricMaker.HistogramImpl;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/** Abstract histogram broken down into buckets by {@link Field} values. */
|
||||
abstract class BucketedHistogram implements BucketedMetric {
|
||||
private final DropWizardMetricMaker metrics;
|
||||
private final String name;
|
||||
private final Description.FieldOrdering ordering;
|
||||
protected final Field<?>[] fields;
|
||||
protected final HistogramImpl total;
|
||||
private final Map<Object, HistogramImpl> cells;
|
||||
private final Object lock = new Object();
|
||||
|
||||
BucketedHistogram(
|
||||
DropWizardMetricMaker metrics, String name, Description desc, Field<?>... fields) {
|
||||
this.metrics = metrics;
|
||||
this.name = name;
|
||||
this.ordering = desc.getFieldOrdering();
|
||||
this.fields = fields;
|
||||
this.total = metrics.newHistogramImpl(name + "_total");
|
||||
this.cells = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
void doRemove() {
|
||||
for (HistogramImpl c : cells.values()) {
|
||||
c.remove();
|
||||
}
|
||||
total.remove();
|
||||
metrics.remove(name);
|
||||
}
|
||||
|
||||
HistogramImpl forceCreate(Object f1, Object f2) {
|
||||
return forceCreate(ImmutableList.of(f1, f2));
|
||||
}
|
||||
|
||||
HistogramImpl forceCreate(Object f1, Object f2, Object f3) {
|
||||
return forceCreate(ImmutableList.of(f1, f2, f3));
|
||||
}
|
||||
|
||||
HistogramImpl forceCreate(Object key) {
|
||||
HistogramImpl c = cells.get(key);
|
||||
if (c != null) {
|
||||
return c;
|
||||
}
|
||||
|
||||
synchronized (lock) {
|
||||
c = cells.get(key);
|
||||
if (c == null) {
|
||||
c = metrics.newHistogramImpl(submetric(key));
|
||||
cells.put(key, c);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
private String submetric(Object key) {
|
||||
return DropWizardMetricMaker.name(ordering, name, name(key));
|
||||
}
|
||||
|
||||
abstract String name(Object key);
|
||||
|
||||
@Override
|
||||
public Metric getTotal() {
|
||||
return total.metric;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Field<?>[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Object, Metric> getCells() {
|
||||
return Maps.transformValues(cells, h -> h.metric);
|
||||
}
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
// 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 com.codahale.metrics.Metric;
|
||||
import com.google.gerrit.common.Nullable;
|
||||
import com.google.gerrit.metrics.Field;
|
||||
import java.util.Map;
|
||||
|
||||
/** Metric broken down into buckets by {@link Field} values. */
|
||||
interface BucketedMetric extends Metric {
|
||||
@Nullable
|
||||
Metric getTotal();
|
||||
|
||||
Field<?>[] getFields();
|
||||
|
||||
Map<?, Metric> getCells();
|
||||
}
|
97
java/com/google/gerrit/metrics/dropwizard/BucketedTimer.java
Normal file
97
java/com/google/gerrit/metrics/dropwizard/BucketedTimer.java
Normal file
@@ -0,0 +1,97 @@
|
||||
// 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 com.codahale.metrics.Metric;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.gerrit.metrics.Description;
|
||||
import com.google.gerrit.metrics.Field;
|
||||
import com.google.gerrit.metrics.dropwizard.DropWizardMetricMaker.TimerImpl;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/** Abstract timer broken down into buckets by {@link Field} values. */
|
||||
abstract class BucketedTimer implements BucketedMetric {
|
||||
private final DropWizardMetricMaker metrics;
|
||||
private final String name;
|
||||
private final Description.FieldOrdering ordering;
|
||||
protected final Field<?>[] fields;
|
||||
protected final TimerImpl total;
|
||||
private final Map<Object, TimerImpl> cells;
|
||||
private final Object lock = new Object();
|
||||
|
||||
BucketedTimer(DropWizardMetricMaker metrics, String name, Description desc, Field<?>... fields) {
|
||||
this.metrics = metrics;
|
||||
this.name = name;
|
||||
this.ordering = desc.getFieldOrdering();
|
||||
this.fields = fields;
|
||||
this.total = metrics.newTimerImpl(name + "_total");
|
||||
this.cells = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
void doRemove() {
|
||||
for (TimerImpl c : cells.values()) {
|
||||
c.remove();
|
||||
}
|
||||
total.remove();
|
||||
metrics.remove(name);
|
||||
}
|
||||
|
||||
TimerImpl forceCreate(Object f1, Object f2) {
|
||||
return forceCreate(ImmutableList.of(f1, f2));
|
||||
}
|
||||
|
||||
TimerImpl forceCreate(Object f1, Object f2, Object f3) {
|
||||
return forceCreate(ImmutableList.of(f1, f2, f3));
|
||||
}
|
||||
|
||||
TimerImpl forceCreate(Object key) {
|
||||
TimerImpl c = cells.get(key);
|
||||
if (c != null) {
|
||||
return c;
|
||||
}
|
||||
|
||||
synchronized (lock) {
|
||||
c = cells.get(key);
|
||||
if (c == null) {
|
||||
c = metrics.newTimerImpl(submetric(key));
|
||||
cells.put(key, c);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
private String submetric(Object key) {
|
||||
return DropWizardMetricMaker.name(ordering, name, name(key));
|
||||
}
|
||||
|
||||
abstract String name(Object key);
|
||||
|
||||
@Override
|
||||
public Metric getTotal() {
|
||||
return total.metric;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Field<?>[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Object, Metric> getCells() {
|
||||
return Maps.transformValues(cells, t -> t.metric);
|
||||
}
|
||||
}
|
68
java/com/google/gerrit/metrics/dropwizard/CallbackGroup.java
Normal file
68
java/com/google/gerrit/metrics/dropwizard/CallbackGroup.java
Normal file
@@ -0,0 +1,68 @@
|
||||
// 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 com.google.common.collect.ImmutableSet;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
/**
|
||||
* Run a user specified trigger only once every 2 seconds.
|
||||
*
|
||||
* <p>This allows the same Runnable trigger to be applied to several metrics. When a recorder is
|
||||
* sampling the related metrics only the first access will perform recomputation. Reading other
|
||||
* related metrics will rely on the already set values for the next several seconds.
|
||||
*/
|
||||
class CallbackGroup implements Runnable {
|
||||
private static final long PERIOD = TimeUnit.SECONDS.toNanos(2);
|
||||
|
||||
private final AtomicLong reloadAt;
|
||||
private final Runnable trigger;
|
||||
private final ImmutableSet<CallbackMetricGlue> metrics;
|
||||
private final Object reloadLock = new Object();
|
||||
|
||||
CallbackGroup(Runnable trigger, ImmutableSet<CallbackMetricGlue> metrics) {
|
||||
this.reloadAt = new AtomicLong(0);
|
||||
this.trigger = trigger;
|
||||
this.metrics = metrics;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (reload()) {
|
||||
synchronized (reloadLock) {
|
||||
for (CallbackMetricGlue m : metrics) {
|
||||
m.beginSet();
|
||||
}
|
||||
trigger.run();
|
||||
for (CallbackMetricGlue m : metrics) {
|
||||
m.endSet();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean reload() {
|
||||
for (; ; ) {
|
||||
long now = System.nanoTime();
|
||||
long next = reloadAt.get();
|
||||
if (next > now) {
|
||||
return false;
|
||||
} else if (reloadAt.compareAndSet(next, now + PERIOD)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
// 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;
|
||||
|
||||
interface CallbackMetricGlue {
|
||||
void beginSet();
|
||||
|
||||
void endSet();
|
||||
|
||||
void register(Runnable trigger);
|
||||
|
||||
void remove();
|
||||
}
|
@@ -0,0 +1,82 @@
|
||||
// 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 com.codahale.metrics.MetricRegistry;
|
||||
import com.google.gerrit.metrics.CallbackMetric0;
|
||||
|
||||
class CallbackMetricImpl0<V> extends CallbackMetric0<V> implements CallbackMetricGlue {
|
||||
@SuppressWarnings("unchecked")
|
||||
static <V> V zeroFor(Class<V> valueClass) {
|
||||
if (valueClass == Integer.class) {
|
||||
return (V) Integer.valueOf(0);
|
||||
} else if (valueClass == Long.class) {
|
||||
return (V) Long.valueOf(0);
|
||||
} else if (valueClass == Double.class) {
|
||||
return (V) Double.valueOf(0);
|
||||
} else if (valueClass == Float.class) {
|
||||
return (V) Float.valueOf(0);
|
||||
} else if (valueClass == String.class) {
|
||||
return (V) "";
|
||||
} else if (valueClass == Boolean.class) {
|
||||
return (V) Boolean.FALSE;
|
||||
} else {
|
||||
throw new IllegalArgumentException("unsupported value type " + valueClass.getName());
|
||||
}
|
||||
}
|
||||
|
||||
private final DropWizardMetricMaker metrics;
|
||||
private final MetricRegistry registry;
|
||||
private final String name;
|
||||
private volatile V value;
|
||||
|
||||
CallbackMetricImpl0(
|
||||
DropWizardMetricMaker metrics, MetricRegistry registry, String name, Class<V> valueType) {
|
||||
this.metrics = metrics;
|
||||
this.registry = registry;
|
||||
this.name = name;
|
||||
this.value = zeroFor(valueType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginSet() {}
|
||||
|
||||
@Override
|
||||
public void endSet() {}
|
||||
|
||||
@Override
|
||||
public void set(V value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
metrics.remove(name);
|
||||
registry.remove(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(Runnable trigger) {
|
||||
registry.register(
|
||||
name,
|
||||
new com.codahale.metrics.Gauge<V>() {
|
||||
@Override
|
||||
public V getValue() {
|
||||
trigger.run();
|
||||
return value;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@@ -0,0 +1,85 @@
|
||||
// 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 com.codahale.metrics.MetricRegistry;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.gerrit.metrics.CallbackMetric1;
|
||||
import com.google.gerrit.metrics.Description;
|
||||
import com.google.gerrit.metrics.Field;
|
||||
|
||||
/** Optimized version of {@link BucketedCallback} for single dimension. */
|
||||
class CallbackMetricImpl1<F1, V> extends BucketedCallback<V> {
|
||||
CallbackMetricImpl1(
|
||||
DropWizardMetricMaker metrics,
|
||||
MetricRegistry registry,
|
||||
String name,
|
||||
Class<V> valueClass,
|
||||
Description desc,
|
||||
Field<F1> field1) {
|
||||
super(metrics, registry, name, valueClass, desc, field1);
|
||||
}
|
||||
|
||||
CallbackMetric1<F1, V> create() {
|
||||
return new Impl1();
|
||||
}
|
||||
|
||||
private final class Impl1 extends CallbackMetric1<F1, V> implements CallbackMetricGlue {
|
||||
@Override
|
||||
public void beginSet() {
|
||||
doBeginSet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(F1 field1, V value) {
|
||||
BucketedCallback<V>.ValueGauge cell = getOrCreate(field1);
|
||||
cell.value = value;
|
||||
cell.set = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prune() {
|
||||
doPrune();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endSet() {
|
||||
doEndSet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forceCreate(F1 field1) {
|
||||
getOrCreate(field1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(Runnable t) {
|
||||
trigger = t;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
doRemove();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
String name(Object field1) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Function<Object, String> fmt = (Function<Object, String>) fields[0].formatter();
|
||||
|
||||
return fmt.apply(field1).replace('/', '-');
|
||||
}
|
||||
}
|
50
java/com/google/gerrit/metrics/dropwizard/CounterImpl1.java
Normal file
50
java/com/google/gerrit/metrics/dropwizard/CounterImpl1.java
Normal file
@@ -0,0 +1,50 @@
|
||||
// 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 com.google.common.base.Function;
|
||||
import com.google.gerrit.metrics.Counter1;
|
||||
import com.google.gerrit.metrics.Description;
|
||||
import com.google.gerrit.metrics.Field;
|
||||
|
||||
/** Optimized version of {@link BucketedCounter} for single dimension. */
|
||||
class CounterImpl1<F1> extends BucketedCounter {
|
||||
CounterImpl1(DropWizardMetricMaker metrics, String name, Description desc, Field<F1> field1) {
|
||||
super(metrics, name, desc, field1);
|
||||
}
|
||||
|
||||
Counter1<F1> counter() {
|
||||
return new Counter1<F1>() {
|
||||
@Override
|
||||
public void incrementBy(F1 field1, long value) {
|
||||
total.incrementBy(value);
|
||||
forceCreate(field1).incrementBy(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
doRemove();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
String name(Object field1) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Function<Object, String> fmt = (Function<Object, String>) fields[0].formatter();
|
||||
|
||||
return fmt.apply(field1).replace('/', '-');
|
||||
}
|
||||
}
|
73
java/com/google/gerrit/metrics/dropwizard/CounterImplN.java
Normal file
73
java/com/google/gerrit/metrics/dropwizard/CounterImplN.java
Normal file
@@ -0,0 +1,73 @@
|
||||
// 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 com.google.common.base.Function;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.gerrit.metrics.Counter2;
|
||||
import com.google.gerrit.metrics.Counter3;
|
||||
import com.google.gerrit.metrics.Description;
|
||||
import com.google.gerrit.metrics.Field;
|
||||
|
||||
/** Generalized implementation of N-dimensional counter metrics. */
|
||||
class CounterImplN extends BucketedCounter implements BucketedMetric {
|
||||
CounterImplN(DropWizardMetricMaker metrics, String name, Description desc, Field<?>... fields) {
|
||||
super(metrics, name, desc, fields);
|
||||
}
|
||||
|
||||
<F1, F2> Counter2<F1, F2> counter2() {
|
||||
return new Counter2<F1, F2>() {
|
||||
@Override
|
||||
public void incrementBy(F1 field1, F2 field2, long value) {
|
||||
total.incrementBy(value);
|
||||
forceCreate(field1, field2).incrementBy(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
doRemove();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
<F1, F2, F3> Counter3<F1, F2, F3> counter3() {
|
||||
return new Counter3<F1, F2, F3>() {
|
||||
@Override
|
||||
public void incrementBy(F1 field1, F2 field2, F3 field3, long value) {
|
||||
total.incrementBy(value);
|
||||
forceCreate(field1, field2, field3).incrementBy(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
doRemove();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
String name(Object key) {
|
||||
ImmutableList<Object> keyList = (ImmutableList<Object>) key;
|
||||
String[] parts = new String[fields.length];
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
Function<Object, String> fmt = (Function<Object, String>) fields[i].formatter();
|
||||
|
||||
parts[i] = fmt.apply(keyList.get(i)).replace('/', '-');
|
||||
}
|
||||
return Joiner.on('/').join(parts);
|
||||
}
|
||||
}
|
@@ -0,0 +1,416 @@
|
||||
// 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 static com.google.gerrit.metrics.dropwizard.MetricResource.METRIC_KIND;
|
||||
import static com.google.gerrit.server.config.ConfigResource.CONFIG_KIND;
|
||||
|
||||
import com.codahale.metrics.Metric;
|
||||
import com.codahale.metrics.MetricRegistry;
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.gerrit.extensions.registration.DynamicMap;
|
||||
import com.google.gerrit.extensions.registration.RegistrationHandle;
|
||||
import com.google.gerrit.extensions.restapi.RestApiModule;
|
||||
import com.google.gerrit.metrics.CallbackMetric;
|
||||
import com.google.gerrit.metrics.CallbackMetric0;
|
||||
import com.google.gerrit.metrics.CallbackMetric1;
|
||||
import com.google.gerrit.metrics.Counter0;
|
||||
import com.google.gerrit.metrics.Counter1;
|
||||
import com.google.gerrit.metrics.Counter2;
|
||||
import com.google.gerrit.metrics.Counter3;
|
||||
import com.google.gerrit.metrics.Description;
|
||||
import com.google.gerrit.metrics.Description.FieldOrdering;
|
||||
import com.google.gerrit.metrics.Field;
|
||||
import com.google.gerrit.metrics.Histogram0;
|
||||
import com.google.gerrit.metrics.Histogram1;
|
||||
import com.google.gerrit.metrics.Histogram2;
|
||||
import com.google.gerrit.metrics.Histogram3;
|
||||
import com.google.gerrit.metrics.MetricMaker;
|
||||
import com.google.gerrit.metrics.Timer0;
|
||||
import com.google.gerrit.metrics.Timer1;
|
||||
import com.google.gerrit.metrics.Timer2;
|
||||
import com.google.gerrit.metrics.Timer3;
|
||||
import com.google.gerrit.metrics.proc.JGitMetricModule;
|
||||
import com.google.gerrit.metrics.proc.ProcMetricModule;
|
||||
import com.google.gerrit.server.cache.CacheMetrics;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Scopes;
|
||||
import com.google.inject.Singleton;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Connects Gerrit metric package onto DropWizard.
|
||||
*
|
||||
* @see <a href="http://www.dropwizard.io/">DropWizard</a>
|
||||
*/
|
||||
@Singleton
|
||||
public class DropWizardMetricMaker extends MetricMaker {
|
||||
public static class ApiModule extends RestApiModule {
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(MetricRegistry.class).in(Scopes.SINGLETON);
|
||||
bind(DropWizardMetricMaker.class).in(Scopes.SINGLETON);
|
||||
bind(MetricMaker.class).to(DropWizardMetricMaker.class);
|
||||
|
||||
install(new ProcMetricModule());
|
||||
install(new JGitMetricModule());
|
||||
}
|
||||
}
|
||||
|
||||
public static class RestModule extends RestApiModule {
|
||||
@Override
|
||||
protected void configure() {
|
||||
DynamicMap.mapOf(binder(), METRIC_KIND);
|
||||
child(CONFIG_KIND, "metrics").to(MetricsCollection.class);
|
||||
get(METRIC_KIND).to(GetMetric.class);
|
||||
bind(CacheMetrics.class);
|
||||
}
|
||||
}
|
||||
|
||||
private final MetricRegistry registry;
|
||||
private final Map<String, BucketedMetric> bucketed;
|
||||
private final Map<String, ImmutableMap<String, String>> descriptions;
|
||||
|
||||
@Inject
|
||||
DropWizardMetricMaker(MetricRegistry registry) {
|
||||
this.registry = registry;
|
||||
this.bucketed = new ConcurrentHashMap<>();
|
||||
this.descriptions = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
Iterable<String> getMetricNames() {
|
||||
return descriptions.keySet();
|
||||
}
|
||||
|
||||
/** Get the underlying metric implementation. */
|
||||
public Metric getMetric(String name) {
|
||||
Metric m = bucketed.get(name);
|
||||
return m != null ? m : registry.getMetrics().get(name);
|
||||
}
|
||||
|
||||
/** Lookup annotations from a metric's {@link Description}. */
|
||||
public ImmutableMap<String, String> getAnnotations(String name) {
|
||||
return descriptions.get(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Counter0 newCounter(String name, Description desc) {
|
||||
checkCounterDescription(name, desc);
|
||||
define(name, desc);
|
||||
return newCounterImpl(name, desc.isRate());
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized <F1> Counter1<F1> newCounter(
|
||||
String name, Description desc, Field<F1> field1) {
|
||||
checkCounterDescription(name, desc);
|
||||
CounterImpl1<F1> m = new CounterImpl1<>(this, name, desc, field1);
|
||||
define(name, desc);
|
||||
bucketed.put(name, m);
|
||||
return m.counter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized <F1, F2> Counter2<F1, F2> newCounter(
|
||||
String name, Description desc, Field<F1> field1, Field<F2> field2) {
|
||||
checkCounterDescription(name, desc);
|
||||
CounterImplN m = new CounterImplN(this, name, desc, field1, field2);
|
||||
define(name, desc);
|
||||
bucketed.put(name, m);
|
||||
return m.counter2();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized <F1, F2, F3> Counter3<F1, F2, F3> newCounter(
|
||||
String name, Description desc, Field<F1> field1, Field<F2> field2, Field<F3> field3) {
|
||||
checkCounterDescription(name, desc);
|
||||
CounterImplN m = new CounterImplN(this, name, desc, field1, field2, field3);
|
||||
define(name, desc);
|
||||
bucketed.put(name, m);
|
||||
return m.counter3();
|
||||
}
|
||||
|
||||
private static void checkCounterDescription(String name, Description desc) {
|
||||
checkMetricName(name);
|
||||
checkArgument(!desc.isConstant(), "counters must not be constant");
|
||||
checkArgument(!desc.isGauge(), "counters must not be gauge");
|
||||
}
|
||||
|
||||
CounterImpl newCounterImpl(String name, boolean isRate) {
|
||||
if (isRate) {
|
||||
final com.codahale.metrics.Meter m = registry.meter(name);
|
||||
return new CounterImpl(name, m) {
|
||||
@Override
|
||||
public void incrementBy(long delta) {
|
||||
checkArgument(delta >= 0, "counter delta must be >= 0");
|
||||
m.mark(delta);
|
||||
}
|
||||
};
|
||||
}
|
||||
final com.codahale.metrics.Counter m = registry.counter(name);
|
||||
return new CounterImpl(name, m) {
|
||||
@Override
|
||||
public void incrementBy(long delta) {
|
||||
checkArgument(delta >= 0, "counter delta must be >= 0");
|
||||
m.inc(delta);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Timer0 newTimer(String name, Description desc) {
|
||||
checkTimerDescription(name, desc);
|
||||
define(name, desc);
|
||||
return newTimerImpl(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized <F1> Timer1<F1> newTimer(String name, Description desc, Field<F1> field1) {
|
||||
checkTimerDescription(name, desc);
|
||||
TimerImpl1<F1> m = new TimerImpl1<>(this, name, desc, field1);
|
||||
define(name, desc);
|
||||
bucketed.put(name, m);
|
||||
return m.timer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized <F1, F2> Timer2<F1, F2> newTimer(
|
||||
String name, Description desc, Field<F1> field1, Field<F2> field2) {
|
||||
checkTimerDescription(name, desc);
|
||||
TimerImplN m = new TimerImplN(this, name, desc, field1, field2);
|
||||
define(name, desc);
|
||||
bucketed.put(name, m);
|
||||
return m.timer2();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized <F1, F2, F3> Timer3<F1, F2, F3> newTimer(
|
||||
String name, Description desc, Field<F1> field1, Field<F2> field2, Field<F3> field3) {
|
||||
checkTimerDescription(name, desc);
|
||||
TimerImplN m = new TimerImplN(this, name, desc, field1, field2, field3);
|
||||
define(name, desc);
|
||||
bucketed.put(name, m);
|
||||
return m.timer3();
|
||||
}
|
||||
|
||||
private static void checkTimerDescription(String name, Description desc) {
|
||||
checkMetricName(name);
|
||||
checkArgument(!desc.isConstant(), "timer must not be constant");
|
||||
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");
|
||||
}
|
||||
|
||||
TimerImpl newTimerImpl(String name) {
|
||||
return new TimerImpl(name, registry.timer(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Histogram0 newHistogram(String name, Description desc) {
|
||||
checkHistogramDescription(name, desc);
|
||||
define(name, desc);
|
||||
return newHistogramImpl(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized <F1> Histogram1<F1> newHistogram(
|
||||
String name, Description desc, Field<F1> field1) {
|
||||
checkHistogramDescription(name, desc);
|
||||
HistogramImpl1<F1> m = new HistogramImpl1<>(this, name, desc, field1);
|
||||
define(name, desc);
|
||||
bucketed.put(name, m);
|
||||
return m.histogram1();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized <F1, F2> Histogram2<F1, F2> newHistogram(
|
||||
String name, Description desc, Field<F1> field1, Field<F2> field2) {
|
||||
checkHistogramDescription(name, desc);
|
||||
HistogramImplN m = new HistogramImplN(this, name, desc, field1, field2);
|
||||
define(name, desc);
|
||||
bucketed.put(name, m);
|
||||
return m.histogram2();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized <F1, F2, F3> Histogram3<F1, F2, F3> newHistogram(
|
||||
String name, Description desc, Field<F1> field1, Field<F2> field2, Field<F3> field3) {
|
||||
checkHistogramDescription(name, desc);
|
||||
HistogramImplN m = new HistogramImplN(this, name, desc, field1, field2, field3);
|
||||
define(name, desc);
|
||||
bucketed.put(name, m);
|
||||
return m.histogram3();
|
||||
}
|
||||
|
||||
private static void checkHistogramDescription(String name, Description desc) {
|
||||
checkMetricName(name);
|
||||
checkArgument(!desc.isConstant(), "histogram must not be constant");
|
||||
checkArgument(!desc.isGauge(), "histogram must not be a gauge");
|
||||
checkArgument(!desc.isRate(), "histogram must not be a rate");
|
||||
checkArgument(desc.isCumulative(), "histogram must be cumulative");
|
||||
}
|
||||
|
||||
HistogramImpl newHistogramImpl(String name) {
|
||||
return new HistogramImpl(name, registry.histogram(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V> CallbackMetric0<V> newCallbackMetric(
|
||||
String name, Class<V> valueClass, Description desc) {
|
||||
checkMetricName(name);
|
||||
define(name, desc);
|
||||
return new CallbackMetricImpl0<>(this, registry, name, valueClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <F1, V> CallbackMetric1<F1, V> newCallbackMetric(
|
||||
String name, Class<V> valueClass, Description desc, Field<F1> field1) {
|
||||
checkMetricName(name);
|
||||
CallbackMetricImpl1<F1, V> m =
|
||||
new CallbackMetricImpl1<>(this, registry, name, valueClass, desc, field1);
|
||||
define(name, desc);
|
||||
bucketed.put(name, m);
|
||||
return m.create();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized RegistrationHandle newTrigger(
|
||||
Set<CallbackMetric<?>> metrics, Runnable trigger) {
|
||||
ImmutableSet<CallbackMetricGlue> all =
|
||||
FluentIterable.from(metrics).transform(m -> (CallbackMetricGlue) m).toSet();
|
||||
|
||||
trigger = new CallbackGroup(trigger, all);
|
||||
for (CallbackMetricGlue m : all) {
|
||||
m.register(trigger);
|
||||
}
|
||||
trigger.run();
|
||||
|
||||
return new RegistrationHandle() {
|
||||
@Override
|
||||
public void remove() {
|
||||
for (CallbackMetricGlue m : all) {
|
||||
m.remove();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
synchronized void remove(String name) {
|
||||
bucketed.remove(name);
|
||||
descriptions.remove(name);
|
||||
}
|
||||
|
||||
private synchronized void define(String name, Description desc) {
|
||||
if (descriptions.containsKey(name)) {
|
||||
ImmutableMap<String, String> annotations = descriptions.get(name);
|
||||
if (!desc.getAnnotations()
|
||||
.get(Description.DESCRIPTION)
|
||||
.equals(annotations.get(Description.DESCRIPTION))) {
|
||||
throw new IllegalStateException(String.format("metric %s already defined", name));
|
||||
}
|
||||
} else {
|
||||
descriptions.put(name, desc.getAnnotations());
|
||||
}
|
||||
}
|
||||
|
||||
private static final Pattern METRIC_NAME_PATTERN =
|
||||
Pattern.compile("[a-zA-Z0-9_-]+(/[a-zA-Z0-9_-]+)*");
|
||||
|
||||
private static void checkMetricName(String name) {
|
||||
checkArgument(
|
||||
METRIC_NAME_PATTERN.matcher(name).matches(),
|
||||
"metric name must match %s",
|
||||
METRIC_NAME_PATTERN.pattern());
|
||||
}
|
||||
|
||||
static String name(Description.FieldOrdering ordering, String codeName, String fieldValues) {
|
||||
if (ordering == FieldOrdering.PREFIX_FIELDS_BASENAME) {
|
||||
int s = codeName.lastIndexOf('/');
|
||||
if (s > 0) {
|
||||
String prefix = codeName.substring(0, s);
|
||||
String metric = codeName.substring(s + 1);
|
||||
return prefix + '/' + fieldValues + '/' + metric;
|
||||
}
|
||||
}
|
||||
return codeName + '/' + fieldValues;
|
||||
}
|
||||
|
||||
abstract class CounterImpl extends Counter0 {
|
||||
private final String name;
|
||||
final Metric metric;
|
||||
|
||||
CounterImpl(String name, Metric metric) {
|
||||
this.name = name;
|
||||
this.metric = metric;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
descriptions.remove(name);
|
||||
registry.remove(name);
|
||||
}
|
||||
}
|
||||
|
||||
class TimerImpl extends Timer0 {
|
||||
private final String name;
|
||||
final com.codahale.metrics.Timer metric;
|
||||
|
||||
private TimerImpl(String name, com.codahale.metrics.Timer metric) {
|
||||
this.name = name;
|
||||
this.metric = metric;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void record(long value, TimeUnit unit) {
|
||||
checkArgument(value >= 0, "timer delta must be >= 0");
|
||||
metric.update(value, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
descriptions.remove(name);
|
||||
registry.remove(name);
|
||||
}
|
||||
}
|
||||
|
||||
class HistogramImpl extends Histogram0 {
|
||||
private final String name;
|
||||
final com.codahale.metrics.Histogram metric;
|
||||
|
||||
private HistogramImpl(String name, com.codahale.metrics.Histogram metric) {
|
||||
this.name = name;
|
||||
this.metric = metric;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void record(long value) {
|
||||
metric.update(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
descriptions.remove(name);
|
||||
registry.remove(name);
|
||||
}
|
||||
}
|
||||
}
|
48
java/com/google/gerrit/metrics/dropwizard/GetMetric.java
Normal file
48
java/com/google/gerrit/metrics/dropwizard/GetMetric.java
Normal file
@@ -0,0 +1,48 @@
|
||||
// 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 com.google.gerrit.extensions.restapi.AuthException;
|
||||
import com.google.gerrit.extensions.restapi.RestReadView;
|
||||
import com.google.gerrit.server.CurrentUser;
|
||||
import com.google.gerrit.server.permissions.GlobalPermission;
|
||||
import com.google.gerrit.server.permissions.PermissionBackend;
|
||||
import com.google.gerrit.server.permissions.PermissionBackendException;
|
||||
import com.google.inject.Inject;
|
||||
import org.kohsuke.args4j.Option;
|
||||
|
||||
class GetMetric implements RestReadView<MetricResource> {
|
||||
private final PermissionBackend permissionBackend;
|
||||
private final CurrentUser user;
|
||||
private final DropWizardMetricMaker metrics;
|
||||
|
||||
@Option(name = "--data-only", usage = "return only values")
|
||||
boolean dataOnly;
|
||||
|
||||
@Inject
|
||||
GetMetric(PermissionBackend permissionBackend, CurrentUser user, DropWizardMetricMaker metrics) {
|
||||
this.permissionBackend = permissionBackend;
|
||||
this.user = user;
|
||||
this.metrics = metrics;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MetricJson apply(MetricResource resource)
|
||||
throws AuthException, PermissionBackendException {
|
||||
permissionBackend.user(user).check(GlobalPermission.VIEW_CACHES);
|
||||
return new MetricJson(
|
||||
resource.getMetric(), metrics.getAnnotations(resource.getName()), dataOnly);
|
||||
}
|
||||
}
|
@@ -0,0 +1,50 @@
|
||||
// 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 com.google.common.base.Function;
|
||||
import com.google.gerrit.metrics.Description;
|
||||
import com.google.gerrit.metrics.Field;
|
||||
import com.google.gerrit.metrics.Histogram1;
|
||||
|
||||
/** Optimized version of {@link BucketedHistogram} for single dimension. */
|
||||
class HistogramImpl1<F1> extends BucketedHistogram implements BucketedMetric {
|
||||
HistogramImpl1(DropWizardMetricMaker metrics, String name, Description desc, Field<F1> field1) {
|
||||
super(metrics, name, desc, field1);
|
||||
}
|
||||
|
||||
Histogram1<F1> histogram1() {
|
||||
return new Histogram1<F1>() {
|
||||
@Override
|
||||
public void record(F1 field1, long value) {
|
||||
total.record(value);
|
||||
forceCreate(field1).record(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
doRemove();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
String name(Object field1) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Function<Object, String> fmt = (Function<Object, String>) fields[0].formatter();
|
||||
|
||||
return fmt.apply(field1).replace('/', '-');
|
||||
}
|
||||
}
|
@@ -0,0 +1,73 @@
|
||||
// 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 com.google.common.base.Function;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.gerrit.metrics.Description;
|
||||
import com.google.gerrit.metrics.Field;
|
||||
import com.google.gerrit.metrics.Histogram2;
|
||||
import com.google.gerrit.metrics.Histogram3;
|
||||
|
||||
/** Generalized implementation of N-dimensional Histogram metrics. */
|
||||
class HistogramImplN extends BucketedHistogram implements BucketedMetric {
|
||||
HistogramImplN(DropWizardMetricMaker metrics, String name, Description desc, Field<?>... fields) {
|
||||
super(metrics, name, desc, fields);
|
||||
}
|
||||
|
||||
<F1, F2> Histogram2<F1, F2> histogram2() {
|
||||
return new Histogram2<F1, F2>() {
|
||||
@Override
|
||||
public void record(F1 field1, F2 field2, long value) {
|
||||
total.record(value);
|
||||
forceCreate(field1, field2).record(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
doRemove();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
<F1, F2, F3> Histogram3<F1, F2, F3> histogram3() {
|
||||
return new Histogram3<F1, F2, F3>() {
|
||||
@Override
|
||||
public void record(F1 field1, F2 field2, F3 field3, long value) {
|
||||
total.record(value);
|
||||
forceCreate(field1, field2, field3).record(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
doRemove();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
String name(Object key) {
|
||||
ImmutableList<Object> keyList = (ImmutableList<Object>) key;
|
||||
String[] parts = new String[fields.length];
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
Function<Object, String> fmt = (Function<Object, String>) fields[i].formatter();
|
||||
|
||||
parts[i] = fmt.apply(keyList.get(i)).replace('/', '-');
|
||||
}
|
||||
return Joiner.on('/').join(parts);
|
||||
}
|
||||
}
|
101
java/com/google/gerrit/metrics/dropwizard/ListMetrics.java
Normal file
101
java/com/google/gerrit/metrics/dropwizard/ListMetrics.java
Normal file
@@ -0,0 +1,101 @@
|
||||
// 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 com.codahale.metrics.Metric;
|
||||
import com.google.gerrit.extensions.restapi.AuthException;
|
||||
import com.google.gerrit.extensions.restapi.RestReadView;
|
||||
import com.google.gerrit.server.CurrentUser;
|
||||
import com.google.gerrit.server.config.ConfigResource;
|
||||
import com.google.gerrit.server.permissions.GlobalPermission;
|
||||
import com.google.gerrit.server.permissions.PermissionBackend;
|
||||
import com.google.gerrit.server.permissions.PermissionBackendException;
|
||||
import com.google.inject.Inject;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
import org.kohsuke.args4j.Option;
|
||||
|
||||
class ListMetrics implements RestReadView<ConfigResource> {
|
||||
private final PermissionBackend permissionBackend;
|
||||
private final CurrentUser user;
|
||||
private final DropWizardMetricMaker metrics;
|
||||
|
||||
@Option(name = "--data-only", usage = "return only values")
|
||||
boolean dataOnly;
|
||||
|
||||
@Option(
|
||||
name = "--prefix",
|
||||
aliases = {"-p"},
|
||||
metaVar = "PREFIX",
|
||||
usage = "match metric by exact match or prefix"
|
||||
)
|
||||
List<String> query = new ArrayList<>();
|
||||
|
||||
@Inject
|
||||
ListMetrics(
|
||||
PermissionBackend permissionBackend, CurrentUser user, DropWizardMetricMaker metrics) {
|
||||
this.permissionBackend = permissionBackend;
|
||||
this.user = user;
|
||||
this.metrics = metrics;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, MetricJson> apply(ConfigResource resource)
|
||||
throws AuthException, PermissionBackendException {
|
||||
permissionBackend.user(user).check(GlobalPermission.VIEW_CACHES);
|
||||
|
||||
SortedMap<String, MetricJson> out = new TreeMap<>();
|
||||
List<String> prefixes = new ArrayList<>(query.size());
|
||||
for (String q : query) {
|
||||
if (q.endsWith("/")) {
|
||||
prefixes.add(q);
|
||||
} else {
|
||||
Metric m = metrics.getMetric(q);
|
||||
if (m != null) {
|
||||
out.put(q, toJson(q, m));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (query.isEmpty() || !prefixes.isEmpty()) {
|
||||
for (String name : metrics.getMetricNames()) {
|
||||
if (include(prefixes, name)) {
|
||||
out.put(name, toJson(name, metrics.getMetric(name)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
private MetricJson toJson(String q, Metric m) {
|
||||
return new MetricJson(m, metrics.getAnnotations(q), dataOnly);
|
||||
}
|
||||
|
||||
private static boolean include(List<String> prefixes, String name) {
|
||||
if (prefixes.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
for (String p : prefixes) {
|
||||
if (name.startsWith(p)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
198
java/com/google/gerrit/metrics/dropwizard/MetricJson.java
Normal file
198
java/com/google/gerrit/metrics/dropwizard/MetricJson.java
Normal file
@@ -0,0 +1,198 @@
|
||||
// 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 com.codahale.metrics.Counter;
|
||||
import com.codahale.metrics.Gauge;
|
||||
import com.codahale.metrics.Histogram;
|
||||
import com.codahale.metrics.Meter;
|
||||
import com.codahale.metrics.Metric;
|
||||
import com.codahale.metrics.Snapshot;
|
||||
import com.codahale.metrics.Timer;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.gerrit.metrics.Description;
|
||||
import com.google.gerrit.metrics.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
class MetricJson {
|
||||
String description;
|
||||
String unit;
|
||||
Boolean constant;
|
||||
Boolean rate;
|
||||
Boolean gauge;
|
||||
Boolean cumulative;
|
||||
|
||||
Long count;
|
||||
Object value;
|
||||
|
||||
Double rate_1m;
|
||||
Double rate_5m;
|
||||
Double rate_15m;
|
||||
Double rate_mean;
|
||||
|
||||
Double p50;
|
||||
Double p75;
|
||||
Double p95;
|
||||
Double p98;
|
||||
Double p99;
|
||||
Double p99_9;
|
||||
|
||||
Double min;
|
||||
Double avg;
|
||||
Double max;
|
||||
Double sum;
|
||||
Double std_dev;
|
||||
|
||||
List<FieldJson> fields;
|
||||
Map<String, Object> buckets;
|
||||
|
||||
MetricJson(Metric metric, ImmutableMap<String, String> atts, boolean dataOnly) {
|
||||
if (!dataOnly) {
|
||||
description = atts.get(Description.DESCRIPTION);
|
||||
unit = atts.get(Description.UNIT);
|
||||
constant = toBool(atts, Description.CONSTANT);
|
||||
rate = toBool(atts, Description.RATE);
|
||||
gauge = toBool(atts, Description.GAUGE);
|
||||
cumulative = toBool(atts, Description.CUMULATIVE);
|
||||
}
|
||||
init(metric, atts);
|
||||
}
|
||||
|
||||
private void init(Metric metric, ImmutableMap<String, String> atts) {
|
||||
if (metric instanceof BucketedMetric) {
|
||||
BucketedMetric m = (BucketedMetric) metric;
|
||||
if (m.getTotal() != null) {
|
||||
init(m.getTotal(), atts);
|
||||
}
|
||||
|
||||
Field<?>[] fieldList = m.getFields();
|
||||
fields = new ArrayList<>(fieldList.length);
|
||||
for (Field<?> f : fieldList) {
|
||||
fields.add(new FieldJson(f));
|
||||
}
|
||||
buckets = makeBuckets(fieldList, m.getCells(), atts);
|
||||
|
||||
} else if (metric instanceof Counter) {
|
||||
Counter c = (Counter) metric;
|
||||
count = c.getCount();
|
||||
|
||||
} else if (metric instanceof Gauge) {
|
||||
Gauge<?> g = (Gauge<?>) metric;
|
||||
value = g.getValue();
|
||||
|
||||
} else if (metric instanceof Meter) {
|
||||
Meter m = (Meter) metric;
|
||||
count = m.getCount();
|
||||
rate_1m = m.getOneMinuteRate();
|
||||
rate_5m = m.getFiveMinuteRate();
|
||||
rate_15m = m.getFifteenMinuteRate();
|
||||
|
||||
} else if (metric instanceof Timer) {
|
||||
Timer m = (Timer) metric;
|
||||
Snapshot s = m.getSnapshot();
|
||||
count = m.getCount();
|
||||
rate_1m = m.getOneMinuteRate();
|
||||
rate_5m = m.getFiveMinuteRate();
|
||||
rate_15m = m.getFifteenMinuteRate();
|
||||
|
||||
double div = Description.getTimeUnit(atts.get(Description.UNIT)).toNanos(1);
|
||||
p50 = s.getMedian() / div;
|
||||
p75 = s.get75thPercentile() / div;
|
||||
p95 = s.get95thPercentile() / div;
|
||||
p98 = s.get98thPercentile() / div;
|
||||
p99 = s.get99thPercentile() / div;
|
||||
p99_9 = s.get999thPercentile() / div;
|
||||
|
||||
min = s.getMin() / div;
|
||||
max = s.getMax() / div;
|
||||
std_dev = s.getStdDev() / div;
|
||||
|
||||
} else if (metric instanceof Histogram) {
|
||||
Histogram m = (Histogram) metric;
|
||||
Snapshot s = m.getSnapshot();
|
||||
count = m.getCount();
|
||||
|
||||
p50 = s.getMedian();
|
||||
p75 = s.get75thPercentile();
|
||||
p95 = s.get95thPercentile();
|
||||
p98 = s.get98thPercentile();
|
||||
p99 = s.get99thPercentile();
|
||||
p99_9 = s.get999thPercentile();
|
||||
|
||||
min = (double) s.getMin();
|
||||
avg = (double) s.getMean();
|
||||
max = (double) s.getMax();
|
||||
sum = s.getMean() * m.getCount();
|
||||
std_dev = s.getStdDev();
|
||||
}
|
||||
}
|
||||
|
||||
private static Boolean toBool(ImmutableMap<String, String> atts, String key) {
|
||||
return Description.TRUE_VALUE.equals(atts.get(key)) ? true : null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static Map<String, Object> makeBuckets(
|
||||
Field<?>[] fields, Map<?, Metric> metrics, ImmutableMap<String, String> atts) {
|
||||
if (fields.length == 1) {
|
||||
Function<Object, String> fmt = (Function<Object, String>) fields[0].formatter();
|
||||
Map<String, Object> out = new TreeMap<>();
|
||||
for (Map.Entry<?, Metric> e : metrics.entrySet()) {
|
||||
out.put(fmt.apply(e.getKey()), new MetricJson(e.getValue(), atts, true));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
Map<String, Object> out = new TreeMap<>();
|
||||
for (Map.Entry<?, Metric> e : metrics.entrySet()) {
|
||||
ImmutableList<Object> keys = (ImmutableList<Object>) e.getKey();
|
||||
Map<String, Object> dst = out;
|
||||
|
||||
for (int i = 0; i < fields.length - 1; i++) {
|
||||
Function<Object, String> fmt = (Function<Object, String>) fields[i].formatter();
|
||||
String key = fmt.apply(keys.get(i));
|
||||
Map<String, Object> t = (Map<String, Object>) dst.get(key);
|
||||
if (t == null) {
|
||||
t = new TreeMap<>();
|
||||
dst.put(key, t);
|
||||
}
|
||||
dst = t;
|
||||
}
|
||||
|
||||
Function<Object, String> fmt =
|
||||
(Function<Object, String>) fields[fields.length - 1].formatter();
|
||||
dst.put(fmt.apply(keys.get(fields.length - 1)), new MetricJson(e.getValue(), atts, true));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
static class FieldJson {
|
||||
String name;
|
||||
String type;
|
||||
String description;
|
||||
|
||||
FieldJson(Field<?> field) {
|
||||
this.name = field.getName();
|
||||
this.description = field.getDescription();
|
||||
this.type =
|
||||
Enum.class.isAssignableFrom(field.getType()) ? field.getType().getSimpleName() : null;
|
||||
}
|
||||
}
|
||||
}
|
@@ -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.dropwizard;
|
||||
|
||||
import com.codahale.metrics.Metric;
|
||||
import com.google.gerrit.extensions.restapi.RestView;
|
||||
import com.google.gerrit.server.config.ConfigResource;
|
||||
import com.google.inject.TypeLiteral;
|
||||
|
||||
class MetricResource extends ConfigResource {
|
||||
static final TypeLiteral<RestView<MetricResource>> METRIC_KIND =
|
||||
new TypeLiteral<RestView<MetricResource>>() {};
|
||||
|
||||
private final String name;
|
||||
private final Metric metric;
|
||||
|
||||
MetricResource(String name, Metric metric) {
|
||||
this.name = name;
|
||||
this.metric = metric;
|
||||
}
|
||||
|
||||
String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
Metric getMetric() {
|
||||
return metric;
|
||||
}
|
||||
}
|
@@ -0,0 +1,76 @@
|
||||
// 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 com.codahale.metrics.Metric;
|
||||
import com.google.gerrit.extensions.registration.DynamicMap;
|
||||
import com.google.gerrit.extensions.restapi.AuthException;
|
||||
import com.google.gerrit.extensions.restapi.ChildCollection;
|
||||
import com.google.gerrit.extensions.restapi.IdString;
|
||||
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
|
||||
import com.google.gerrit.extensions.restapi.RestView;
|
||||
import com.google.gerrit.server.CurrentUser;
|
||||
import com.google.gerrit.server.config.ConfigResource;
|
||||
import com.google.gerrit.server.permissions.GlobalPermission;
|
||||
import com.google.gerrit.server.permissions.PermissionBackend;
|
||||
import com.google.gerrit.server.permissions.PermissionBackendException;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
@Singleton
|
||||
class MetricsCollection implements ChildCollection<ConfigResource, MetricResource> {
|
||||
private final DynamicMap<RestView<MetricResource>> views;
|
||||
private final Provider<ListMetrics> list;
|
||||
private final PermissionBackend permissionBackend;
|
||||
private final Provider<CurrentUser> user;
|
||||
private final DropWizardMetricMaker metrics;
|
||||
|
||||
@Inject
|
||||
MetricsCollection(
|
||||
DynamicMap<RestView<MetricResource>> views,
|
||||
Provider<ListMetrics> list,
|
||||
PermissionBackend permissionBackend,
|
||||
Provider<CurrentUser> user,
|
||||
DropWizardMetricMaker metrics) {
|
||||
this.views = views;
|
||||
this.list = list;
|
||||
this.permissionBackend = permissionBackend;
|
||||
this.user = user;
|
||||
this.metrics = metrics;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicMap<RestView<MetricResource>> views() {
|
||||
return views;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestView<ConfigResource> list() {
|
||||
return list.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MetricResource parse(ConfigResource parent, IdString id)
|
||||
throws ResourceNotFoundException, AuthException, PermissionBackendException {
|
||||
permissionBackend.user(user).check(GlobalPermission.VIEW_CACHES);
|
||||
|
||||
Metric metric = metrics.getMetric(id.get());
|
||||
if (metric == null) {
|
||||
throw new ResourceNotFoundException(id.get());
|
||||
}
|
||||
return new MetricResource(id.get(), metric);
|
||||
}
|
||||
}
|
51
java/com/google/gerrit/metrics/dropwizard/TimerImpl1.java
Normal file
51
java/com/google/gerrit/metrics/dropwizard/TimerImpl1.java
Normal file
@@ -0,0 +1,51 @@
|
||||
// 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 com.google.common.base.Function;
|
||||
import com.google.gerrit.metrics.Description;
|
||||
import com.google.gerrit.metrics.Field;
|
||||
import com.google.gerrit.metrics.Timer1;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/** Optimized version of {@link BucketedTimer} for single dimension. */
|
||||
class TimerImpl1<F1> extends BucketedTimer implements BucketedMetric {
|
||||
TimerImpl1(DropWizardMetricMaker metrics, String name, Description desc, Field<F1> field1) {
|
||||
super(metrics, name, desc, field1);
|
||||
}
|
||||
|
||||
Timer1<F1> timer() {
|
||||
return new Timer1<F1>() {
|
||||
@Override
|
||||
public void record(F1 field1, long value, TimeUnit unit) {
|
||||
total.record(value, unit);
|
||||
forceCreate(field1).record(value, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
doRemove();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
String name(Object field1) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Function<Object, String> fmt = (Function<Object, String>) fields[0].formatter();
|
||||
|
||||
return fmt.apply(field1).replace('/', '-');
|
||||
}
|
||||
}
|
74
java/com/google/gerrit/metrics/dropwizard/TimerImplN.java
Normal file
74
java/com/google/gerrit/metrics/dropwizard/TimerImplN.java
Normal file
@@ -0,0 +1,74 @@
|
||||
// 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 com.google.common.base.Function;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.gerrit.metrics.Description;
|
||||
import com.google.gerrit.metrics.Field;
|
||||
import com.google.gerrit.metrics.Timer2;
|
||||
import com.google.gerrit.metrics.Timer3;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/** Generalized implementation of N-dimensional timer metrics. */
|
||||
class TimerImplN extends BucketedTimer implements BucketedMetric {
|
||||
TimerImplN(DropWizardMetricMaker metrics, String name, Description desc, Field<?>... fields) {
|
||||
super(metrics, name, desc, fields);
|
||||
}
|
||||
|
||||
<F1, F2> Timer2<F1, F2> timer2() {
|
||||
return new Timer2<F1, F2>() {
|
||||
@Override
|
||||
public void record(F1 field1, F2 field2, long value, TimeUnit unit) {
|
||||
total.record(value, unit);
|
||||
forceCreate(field1, field2).record(value, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
doRemove();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
<F1, F2, F3> Timer3<F1, F2, F3> timer3() {
|
||||
return new Timer3<F1, F2, F3>() {
|
||||
@Override
|
||||
public void record(F1 field1, F2 field2, F3 field3, long value, TimeUnit unit) {
|
||||
total.record(value, unit);
|
||||
forceCreate(field1, field2, field3).record(value, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
doRemove();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
String name(Object key) {
|
||||
ImmutableList<Object> keyList = (ImmutableList<Object>) key;
|
||||
String[] parts = new String[fields.length];
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
Function<Object, String> fmt = (Function<Object, String>) fields[i].formatter();
|
||||
|
||||
parts[i] = fmt.apply(keyList.get(i)).replace('/', '-');
|
||||
}
|
||||
return Joiner.on('/').join(parts);
|
||||
}
|
||||
}
|
50
java/com/google/gerrit/metrics/proc/JGitMetricModule.java
Normal file
50
java/com/google/gerrit/metrics/proc/JGitMetricModule.java
Normal file
@@ -0,0 +1,50 @@
|
||||
// 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.proc;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.gerrit.metrics.Description;
|
||||
import com.google.gerrit.metrics.Description.Units;
|
||||
import com.google.gerrit.metrics.MetricMaker;
|
||||
import org.eclipse.jgit.internal.storage.file.WindowCacheStatAccessor;
|
||||
|
||||
public class JGitMetricModule extends MetricModule {
|
||||
@Override
|
||||
protected void configure(MetricMaker metrics) {
|
||||
metrics.newCallbackMetric(
|
||||
"jgit/block_cache/cache_used",
|
||||
Long.class,
|
||||
new Description("Bytes of memory retained in JGit block cache.")
|
||||
.setGauge()
|
||||
.setUnit(Units.BYTES),
|
||||
new Supplier<Long>() {
|
||||
@Override
|
||||
public Long get() {
|
||||
return WindowCacheStatAccessor.getOpenBytes();
|
||||
}
|
||||
});
|
||||
|
||||
metrics.newCallbackMetric(
|
||||
"jgit/block_cache/open_files",
|
||||
Integer.class,
|
||||
new Description("File handles held open by JGit block cache.").setGauge().setUnit("fds"),
|
||||
new Supplier<Integer>() {
|
||||
@Override
|
||||
public Integer get() {
|
||||
return WindowCacheStatAccessor.getOpenFiles();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
43
java/com/google/gerrit/metrics/proc/MetricModule.java
Normal file
43
java/com/google/gerrit/metrics/proc/MetricModule.java
Normal file
@@ -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.proc;
|
||||
|
||||
import com.google.gerrit.extensions.events.LifecycleListener;
|
||||
import com.google.gerrit.lifecycle.LifecycleModule;
|
||||
import com.google.gerrit.metrics.MetricMaker;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
/** Guice module to configure metrics on server startup. */
|
||||
public abstract class MetricModule extends LifecycleModule {
|
||||
/** Configure metrics during server startup. */
|
||||
protected abstract void configure(MetricMaker metrics);
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
listener()
|
||||
.toInstance(
|
||||
new LifecycleListener() {
|
||||
@Inject MetricMaker metrics;
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
configure(metrics);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {}
|
||||
});
|
||||
}
|
||||
}
|
@@ -0,0 +1,77 @@
|
||||
// Copyright (C) 2017 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.proc;
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.OperatingSystemMXBean;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
class OperatingSystemMXBeanProvider {
|
||||
private static final Logger log = LoggerFactory.getLogger(OperatingSystemMXBeanProvider.class);
|
||||
|
||||
private final OperatingSystemMXBean sys;
|
||||
private final Method getProcessCpuTime;
|
||||
private final Method getOpenFileDescriptorCount;
|
||||
|
||||
static class Factory {
|
||||
static OperatingSystemMXBeanProvider create() {
|
||||
OperatingSystemMXBean sys = ManagementFactory.getOperatingSystemMXBean();
|
||||
for (String name :
|
||||
Arrays.asList(
|
||||
"com.sun.management.UnixOperatingSystemMXBean",
|
||||
"com.ibm.lang.management.UnixOperatingSystemMXBean")) {
|
||||
try {
|
||||
Class<?> impl = Class.forName(name);
|
||||
if (impl.isInstance(sys)) {
|
||||
return new OperatingSystemMXBeanProvider(sys);
|
||||
}
|
||||
} catch (ReflectiveOperationException e) {
|
||||
log.debug(String.format("No implementation for %s: %s", name, e.getMessage()));
|
||||
}
|
||||
}
|
||||
log.warn("No implementation of UnixOperatingSystemMXBean found");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private OperatingSystemMXBeanProvider(OperatingSystemMXBean sys)
|
||||
throws ReflectiveOperationException {
|
||||
this.sys = sys;
|
||||
getProcessCpuTime = sys.getClass().getMethod("getProcessCpuTime", new Class<?>[] {});
|
||||
getProcessCpuTime.setAccessible(true);
|
||||
getOpenFileDescriptorCount =
|
||||
sys.getClass().getMethod("getOpenFileDescriptorCount", new Class<?>[] {});
|
||||
getOpenFileDescriptorCount.setAccessible(true);
|
||||
}
|
||||
|
||||
public long getProcessCpuTime() {
|
||||
try {
|
||||
return (long) getProcessCpuTime.invoke(sys, new Object[] {});
|
||||
} catch (ReflectiveOperationException e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public long getOpenFileDescriptorCount() {
|
||||
try {
|
||||
return (long) getOpenFileDescriptorCount.invoke(sys, new Object[] {});
|
||||
} catch (ReflectiveOperationException e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
209
java/com/google/gerrit/metrics/proc/ProcMetricModule.java
Normal file
209
java/com/google/gerrit/metrics/proc/ProcMetricModule.java
Normal file
@@ -0,0 +1,209 @@
|
||||
// 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.proc;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.gerrit.common.Version;
|
||||
import com.google.gerrit.metrics.CallbackMetric;
|
||||
import com.google.gerrit.metrics.CallbackMetric0;
|
||||
import com.google.gerrit.metrics.CallbackMetric1;
|
||||
import com.google.gerrit.metrics.Description;
|
||||
import com.google.gerrit.metrics.Description.Units;
|
||||
import com.google.gerrit.metrics.Field;
|
||||
import com.google.gerrit.metrics.MetricMaker;
|
||||
import java.lang.management.GarbageCollectorMXBean;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.MemoryMXBean;
|
||||
import java.lang.management.MemoryUsage;
|
||||
import java.lang.management.ThreadMXBean;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class ProcMetricModule extends MetricModule {
|
||||
@Override
|
||||
protected void configure(MetricMaker metrics) {
|
||||
buildLabel(metrics);
|
||||
procUptime(metrics);
|
||||
procCpuUsage(metrics);
|
||||
procJvmGc(metrics);
|
||||
procJvmMemory(metrics);
|
||||
procJvmThread(metrics);
|
||||
}
|
||||
|
||||
private void buildLabel(MetricMaker metrics) {
|
||||
metrics.newConstantMetric(
|
||||
"build/label",
|
||||
Strings.nullToEmpty(Version.getVersion()),
|
||||
new Description("Version of Gerrit server software"));
|
||||
}
|
||||
|
||||
private void procUptime(MetricMaker metrics) {
|
||||
metrics.newConstantMetric(
|
||||
"proc/birth_timestamp",
|
||||
Long.valueOf(TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis())),
|
||||
new Description("Time at which the process started").setUnit(Units.MICROSECONDS));
|
||||
|
||||
metrics.newCallbackMetric(
|
||||
"proc/uptime",
|
||||
Long.class,
|
||||
new Description("Uptime of this process").setUnit(Units.MILLISECONDS),
|
||||
new Supplier<Long>() {
|
||||
@Override
|
||||
public Long get() {
|
||||
return ManagementFactory.getRuntimeMXBean().getUptime();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void procCpuUsage(MetricMaker metrics) {
|
||||
final OperatingSystemMXBeanProvider provider = OperatingSystemMXBeanProvider.Factory.create();
|
||||
|
||||
if (provider == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (provider.getProcessCpuTime() != -1) {
|
||||
metrics.newCallbackMetric(
|
||||
"proc/cpu/usage",
|
||||
Double.class,
|
||||
new Description("CPU time used by the process").setCumulative().setUnit(Units.SECONDS),
|
||||
new Supplier<Double>() {
|
||||
@Override
|
||||
public Double get() {
|
||||
return provider.getProcessCpuTime() / 1e9;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (provider.getOpenFileDescriptorCount() != -1) {
|
||||
metrics.newCallbackMetric(
|
||||
"proc/num_open_fds",
|
||||
Long.class,
|
||||
new Description("Number of open file descriptors").setGauge().setUnit("fds"),
|
||||
new Supplier<Long>() {
|
||||
@Override
|
||||
public Long get() {
|
||||
return provider.getOpenFileDescriptorCount();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void procJvmMemory(MetricMaker metrics) {
|
||||
CallbackMetric0<Long> heapCommitted =
|
||||
metrics.newCallbackMetric(
|
||||
"proc/jvm/memory/heap_committed",
|
||||
Long.class,
|
||||
new Description("Amount of memory guaranteed for user objects.")
|
||||
.setGauge()
|
||||
.setUnit(Units.BYTES));
|
||||
|
||||
CallbackMetric0<Long> heapUsed =
|
||||
metrics.newCallbackMetric(
|
||||
"proc/jvm/memory/heap_used",
|
||||
Long.class,
|
||||
new Description("Amount of memory holding user objects.")
|
||||
.setGauge()
|
||||
.setUnit(Units.BYTES));
|
||||
|
||||
CallbackMetric0<Long> nonHeapCommitted =
|
||||
metrics.newCallbackMetric(
|
||||
"proc/jvm/memory/non_heap_committed",
|
||||
Long.class,
|
||||
new Description("Amount of memory guaranteed for classes, etc.")
|
||||
.setGauge()
|
||||
.setUnit(Units.BYTES));
|
||||
|
||||
CallbackMetric0<Long> nonHeapUsed =
|
||||
metrics.newCallbackMetric(
|
||||
"proc/jvm/memory/non_heap_used",
|
||||
Long.class,
|
||||
new Description("Amount of memory holding classes, etc.")
|
||||
.setGauge()
|
||||
.setUnit(Units.BYTES));
|
||||
|
||||
CallbackMetric0<Integer> objectPendingFinalizationCount =
|
||||
metrics.newCallbackMetric(
|
||||
"proc/jvm/memory/object_pending_finalization_count",
|
||||
Integer.class,
|
||||
new Description("Approximate number of objects needing finalization.")
|
||||
.setGauge()
|
||||
.setUnit("objects"));
|
||||
|
||||
MemoryMXBean memory = ManagementFactory.getMemoryMXBean();
|
||||
metrics.newTrigger(
|
||||
ImmutableSet.<CallbackMetric<?>>of(
|
||||
heapCommitted, heapUsed, nonHeapCommitted, nonHeapUsed, objectPendingFinalizationCount),
|
||||
() -> {
|
||||
try {
|
||||
MemoryUsage stats = memory.getHeapMemoryUsage();
|
||||
heapCommitted.set(stats.getCommitted());
|
||||
heapUsed.set(stats.getUsed());
|
||||
} catch (IllegalArgumentException e) {
|
||||
// MXBean may throw due to a bug in Java 7; ignore.
|
||||
}
|
||||
|
||||
MemoryUsage stats = memory.getNonHeapMemoryUsage();
|
||||
nonHeapCommitted.set(stats.getCommitted());
|
||||
nonHeapUsed.set(stats.getUsed());
|
||||
|
||||
objectPendingFinalizationCount.set(memory.getObjectPendingFinalizationCount());
|
||||
});
|
||||
}
|
||||
|
||||
private void procJvmGc(MetricMaker metrics) {
|
||||
CallbackMetric1<String, Long> gcCount =
|
||||
metrics.newCallbackMetric(
|
||||
"proc/jvm/gc/count",
|
||||
Long.class,
|
||||
new Description("Number of GCs").setCumulative(),
|
||||
Field.ofString("gc_name", "The name of the garbage collector"));
|
||||
|
||||
CallbackMetric1<String, Long> gcTime =
|
||||
metrics.newCallbackMetric(
|
||||
"proc/jvm/gc/time",
|
||||
Long.class,
|
||||
new Description("Approximate accumulated GC elapsed time")
|
||||
.setCumulative()
|
||||
.setUnit(Units.MILLISECONDS),
|
||||
Field.ofString("gc_name", "The name of the garbage collector"));
|
||||
|
||||
metrics.newTrigger(
|
||||
gcCount,
|
||||
gcTime,
|
||||
() -> {
|
||||
for (GarbageCollectorMXBean gc : ManagementFactory.getGarbageCollectorMXBeans()) {
|
||||
long count = gc.getCollectionCount();
|
||||
if (count != -1) {
|
||||
gcCount.set(gc.getName(), count);
|
||||
}
|
||||
long time = gc.getCollectionTime();
|
||||
if (time != -1) {
|
||||
gcTime.set(gc.getName(), time);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void procJvmThread(MetricMaker metrics) {
|
||||
ThreadMXBean thread = ManagementFactory.getThreadMXBean();
|
||||
metrics.newCallbackMetric(
|
||||
"proc/jvm/thread/num_live",
|
||||
Integer.class,
|
||||
new Description("Current live thread count").setGauge().setUnit("threads"),
|
||||
() -> thread.getThreadCount());
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user