Export standard JVM and JGit metrics
Add support for constant metrics. These are exported values that are computed only once per process and cannot change without the JVM shutting down and starting back up again. Export proc/birth_timestamp as build/label to describe when the process launched and what version it is. These are constants. Add support for CallbackMetric1, allowing for some JVM GC data to be exported. These can be useful to track Java GC overheads over time. Export JGit block cache metrics along with high level JVM memory usage. Change-Id: I9bb24a466eab99cf93358b105ff0c7333bd78ea2
This commit is contained in:
parent
b65b83a5f6
commit
98d198c701
@ -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;
|
||||
|
||||
/**
|
||||
* 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. */
|
||||
public abstract void forceCreate(F1 field1);
|
||||
}
|
@ -28,6 +28,7 @@ public class Description {
|
||||
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";
|
||||
|
||||
@ -76,6 +77,16 @@ public class Description {
|
||||
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.
|
||||
*/
|
||||
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
|
||||
@ -111,6 +122,11 @@ public class Description {
|
||||
return this;
|
||||
}
|
||||
|
||||
/** True if the metric value never changes after startup. */
|
||||
public boolean isConstant() {
|
||||
return TRUE_VALUE.equals(annotations.get(CONSTANT));
|
||||
}
|
||||
|
||||
/** True if the metric may be interpreted as a rate over time. */
|
||||
public boolean isRate() {
|
||||
return TRUE_VALUE.equals(annotations.get(RATE));
|
||||
|
@ -100,6 +100,16 @@ public class DisabledMetricMaker extends MetricMaker {
|
||||
};
|
||||
}
|
||||
|
||||
@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) {
|
||||
|
@ -46,6 +46,27 @@ public abstract class MetricMaker {
|
||||
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, final V value, Description desc) {
|
||||
desc.setConstant();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<V> type = (Class<V>) value.getClass();
|
||||
final CallbackMetric0<V> metric = newCallbackMetric(name, type, desc);
|
||||
newTrigger(metric, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
metric.set(value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantaneous reading of a value.
|
||||
*
|
||||
@ -80,6 +101,9 @@ public abstract class MetricMaker {
|
||||
/** Instantaneous reading of a single value. */
|
||||
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}. */
|
||||
public RegistrationHandle newTrigger(CallbackMetric<?> metric1, Runnable trigger) {
|
||||
|
@ -0,0 +1,124 @@
|
||||
// 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.collect.ImmutableList;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.gerrit.metrics.Description;
|
||||
import com.google.gerrit.metrics.Field;
|
||||
|
||||
import com.codahale.metrics.Gauge;
|
||||
import com.codahale.metrics.Metric;
|
||||
import com.codahale.metrics.MetricRegistry;
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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 (cells) {
|
||||
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,
|
||||
new Function<ValueGauge, Metric> () {
|
||||
@Override
|
||||
public Metric apply(ValueGauge in) {
|
||||
return in;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
final class ValueGauge implements Gauge<V> {
|
||||
volatile V value = zero;
|
||||
|
||||
@Override
|
||||
public V getValue() {
|
||||
Runnable t = trigger;
|
||||
if (t != null) {
|
||||
t.run();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
// 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 register(Runnable trigger);
|
||||
}
|
@ -16,7 +16,11 @@ package com.google.gerrit.metrics.dropwizard;
|
||||
|
||||
import com.google.gerrit.metrics.CallbackMetric0;
|
||||
|
||||
class CallbackMetricImpl0<V> extends CallbackMetric0<V> {
|
||||
import com.codahale.metrics.MetricRegistry;
|
||||
|
||||
class CallbackMetricImpl0<V>
|
||||
extends CallbackMetric0<V>
|
||||
implements CallbackMetricGlue {
|
||||
@SuppressWarnings("unchecked")
|
||||
static <V> V zeroFor(Class<V> valueClass) {
|
||||
if (valueClass == Integer.class) {
|
||||
@ -37,10 +41,15 @@ class CallbackMetricImpl0<V> extends CallbackMetric0<V> {
|
||||
}
|
||||
}
|
||||
|
||||
final String name;
|
||||
private V value;
|
||||
private final DropWizardMetricMaker metrics;
|
||||
private final MetricRegistry registry;
|
||||
private final String name;
|
||||
private volatile V value;
|
||||
|
||||
CallbackMetricImpl0(String name, Class<V> valueType) {
|
||||
CallbackMetricImpl0(DropWizardMetricMaker metrics, MetricRegistry registry,
|
||||
String name, Class<V> valueType) {
|
||||
this.metrics = metrics;
|
||||
this.registry = registry;
|
||||
this.name = name;
|
||||
this.value = zeroFor(valueType);
|
||||
}
|
||||
@ -52,16 +61,18 @@ class CallbackMetricImpl0<V> extends CallbackMetric0<V> {
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
// Triggers register and remove the metric.
|
||||
metrics.remove(name);
|
||||
registry.remove(name);
|
||||
}
|
||||
|
||||
com.codahale.metrics.Gauge<V> gauge(final Runnable trigger) {
|
||||
return new com.codahale.metrics.Gauge<V>() {
|
||||
@Override
|
||||
public void register(final Runnable trigger) {
|
||||
registry.register(name, new com.codahale.metrics.Gauge<V>() {
|
||||
@Override
|
||||
public V getValue() {
|
||||
trigger.run();
|
||||
return value;
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
// 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.CallbackMetric1;
|
||||
import com.google.gerrit.metrics.Description;
|
||||
import com.google.gerrit.metrics.Field;
|
||||
|
||||
import com.codahale.metrics.MetricRegistry;
|
||||
|
||||
/** 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 set(F1 field1, V value) {
|
||||
getOrCreate(field1).value = value;
|
||||
}
|
||||
|
||||
@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('/', '-');
|
||||
}
|
||||
}
|
@ -24,18 +24,21 @@ 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.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.Description.FieldOrdering;
|
||||
import com.google.gerrit.metrics.proc.JGitMetricModule;
|
||||
import com.google.gerrit.metrics.proc.ProcMetricModule;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Scopes;
|
||||
import com.google.inject.Singleton;
|
||||
@ -64,6 +67,9 @@ public class DropWizardMetricMaker extends MetricMaker {
|
||||
bind(DropWizardMetricMaker.class).in(Scopes.SINGLETON);
|
||||
bind(MetricMaker.class).to(DropWizardMetricMaker.class);
|
||||
|
||||
install(new ProcMetricModule());
|
||||
install(new JGitMetricModule());
|
||||
|
||||
DynamicMap.mapOf(binder(), METRIC_KIND);
|
||||
child(CONFIG_KIND, "metrics").to(MetricsCollection.class);
|
||||
get(METRIC_KIND).to(GetMetric.class);
|
||||
@ -137,6 +143,7 @@ public class DropWizardMetricMaker extends MetricMaker {
|
||||
}
|
||||
|
||||
private static void checkCounterDescription(Description desc) {
|
||||
checkArgument(!desc.isConstant(), "counters must not be constant");
|
||||
checkArgument(!desc.isGauge(), "counters must not be gauge");
|
||||
}
|
||||
|
||||
@ -200,6 +207,7 @@ public class DropWizardMetricMaker extends MetricMaker {
|
||||
}
|
||||
|
||||
private static void checkTimerDescription(Description desc) {
|
||||
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");
|
||||
@ -214,37 +222,35 @@ public class DropWizardMetricMaker extends MetricMaker {
|
||||
public <V> CallbackMetric0<V> newCallbackMetric(
|
||||
String name, Class<V> valueClass, Description desc) {
|
||||
define(name, desc);
|
||||
return new CallbackMetricImpl0<>(name, valueClass);
|
||||
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) {
|
||||
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) {
|
||||
if (metrics.size() > 1) {
|
||||
trigger = new CallbackGroup(trigger);
|
||||
}
|
||||
trigger = new CallbackGroup(trigger);
|
||||
|
||||
for (CallbackMetric<?> m : metrics) {
|
||||
CallbackMetricImpl0<?> metric = (CallbackMetricImpl0<?>) m;
|
||||
if (registry.getMetrics().containsKey(metric.name)) {
|
||||
throw new IllegalStateException(String.format(
|
||||
"metric %s already configured", metric.name));
|
||||
}
|
||||
}
|
||||
|
||||
final List<String> names = new ArrayList<>(metrics.size());
|
||||
for (CallbackMetric<?> m : metrics) {
|
||||
CallbackMetricImpl0<?> metric = (CallbackMetricImpl0<?>) m;
|
||||
registry.register(metric.name, metric.gauge(trigger));
|
||||
names.add(metric.name);
|
||||
((CallbackMetricGlue) m).register(trigger);
|
||||
}
|
||||
trigger.run();
|
||||
|
||||
final List<CallbackMetric<?>> all = new ArrayList<>(metrics);
|
||||
return new RegistrationHandle() {
|
||||
@Override
|
||||
public void remove() {
|
||||
for (String name : names) {
|
||||
descriptions.remove(name);
|
||||
registry.remove(name);
|
||||
for (CallbackMetric<?> m : all) {
|
||||
m.remove();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -35,6 +35,7 @@ import java.util.TreeMap;
|
||||
class MetricJson {
|
||||
String description;
|
||||
String unit;
|
||||
Boolean constant;
|
||||
Boolean rate;
|
||||
Boolean gauge;
|
||||
Boolean cumulative;
|
||||
@ -65,6 +66,7 @@ class MetricJson {
|
||||
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);
|
||||
|
@ -0,0 +1,53 @@
|
||||
// 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.MetricMaker;
|
||||
import com.google.gerrit.metrics.Description.Units;
|
||||
|
||||
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();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -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,226 @@
|
||||
// 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 com.sun.management.OperatingSystemMXBean;
|
||||
import com.sun.management.UnixOperatingSystemMXBean;
|
||||
|
||||
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;
|
||||
|
||||
@SuppressWarnings("restriction")
|
||||
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 OperatingSystemMXBean sys =
|
||||
(OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
|
||||
if (sys.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 sys.getProcessCpuTime() / 1e9;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (sys instanceof UnixOperatingSystemMXBean) {
|
||||
final UnixOperatingSystemMXBean unix = (UnixOperatingSystemMXBean) sys;
|
||||
if (unix.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 unix.getOpenFileDescriptorCount();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void procJvmMemory(MetricMaker metrics) {
|
||||
final 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));
|
||||
|
||||
final CallbackMetric0<Long> heapUsed = metrics.newCallbackMetric(
|
||||
"proc/jvm/memory/heap_used",
|
||||
Long.class,
|
||||
new Description("Amount of memory holding user objects.")
|
||||
.setGauge()
|
||||
.setUnit(Units.BYTES));
|
||||
|
||||
final 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));
|
||||
|
||||
final 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));
|
||||
|
||||
final 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"));
|
||||
|
||||
final MemoryMXBean memory = ManagementFactory.getMemoryMXBean();
|
||||
metrics.newTrigger(
|
||||
ImmutableSet.<CallbackMetric<?>> of(
|
||||
heapCommitted, heapUsed, nonHeapCommitted,
|
||||
nonHeapUsed, objectPendingFinalizationCount),
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
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) {
|
||||
final 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"));
|
||||
|
||||
final 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, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
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) {
|
||||
final ThreadMXBean thread = ManagementFactory.getThreadMXBean();
|
||||
metrics.newCallbackMetric(
|
||||
"proc/jvm/thread/num_live",
|
||||
Integer.class,
|
||||
new Description("Current live thread count")
|
||||
.setGauge()
|
||||
.setUnit("threads"),
|
||||
new Supplier<Integer>() {
|
||||
@Override
|
||||
public Integer get() {
|
||||
return thread.getThreadCount();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -18,6 +18,7 @@ import com.google.gerrit.extensions.events.LifecycleListener;
|
||||
import com.google.gerrit.extensions.registration.RegistrationHandle;
|
||||
import com.google.gerrit.metrics.CallbackMetric;
|
||||
import com.google.gerrit.metrics.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;
|
||||
@ -124,6 +125,15 @@ class PluginMetricMaker extends MetricMaker implements LifecycleListener {
|
||||
return m;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <F1, V> CallbackMetric1<F1, V> newCallbackMetric(String name,
|
||||
Class<V> valueClass, Description desc, Field<F1> field1) {
|
||||
CallbackMetric1<F1, V> m =
|
||||
root.newCallbackMetric(prefix + name, valueClass, desc, field1);
|
||||
cleanup.add(m);
|
||||
return m;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegistrationHandle newTrigger(Set<CallbackMetric<?>> metrics,
|
||||
Runnable trigger) {
|
||||
|
Loading…
Reference in New Issue
Block a user