| // 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(); |
| } |
| } |