blob: f5963afaa3c62db39314e4e08652e70550ee0a53 [file] [log] [blame]
// 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;
}
/** Returns true if the metric value never changes after startup. */
public boolean isConstant() {
return TRUE_VALUE.equals(annotations.get(CONSTANT));
}
/** Returns true if the metric may be interpreted as a rate over time. */
public boolean isRate() {
return TRUE_VALUE.equals(annotations.get(RATE));
}
/** Returns true if the metric is an instantaneous sample. */
public boolean isGauge() {
return TRUE_VALUE.equals(annotations.get(GAUGE));
}
/** Returns true if the metric accumulates over the lifespan of the process. */
public boolean isCumulative() {
return TRUE_VALUE.equals(annotations.get(CUMULATIVE));
}
/** Returns 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;
}
/** Returns an immutable copy of all annotations (configurable properties). */
public ImmutableMap<String, String> getAnnotations() {
return ImmutableMap.copyOf(annotations);
}
@Override
public String toString() {
return annotations.toString();
}
}