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