All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.api.control.aggregator.MetricValues Maven / Gradle / Ivy

There is a newer version: 1.0.14
Show newest version
/*
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * 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.api.control.aggregator;

import com.google.api.MetricDescriptor.MetricKind;
import com.google.api.control.model.Distributions;
import com.google.api.control.model.Timestamps;
import com.google.api.servicecontrol.v1.MetricValue;
import com.google.api.servicecontrol.v1.MetricValue.Builder;
import com.google.common.hash.HashCode;
import com.google.common.hash.Hasher;
import com.google.common.hash.Hashing;

import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Provide functions that enable aggregation of {@link MetricValue}s.
 */
public final class MetricValues {
  private static final String MSG_NOT_MERGABLE = "Metric type not mergeabe";
  private static final String MSG_CANNOT_MERGE_DIFFERENT_TYPES =
      "Cannot merge metrics with different types of value";
  private static final Logger log = Logger.getLogger(MetricValues.class.getName());

  private MetricValues() {}

  /**
   * Updates {@code h} with the contents of {@code value}.
   *
   * @param h a {@link Hasher}
   * @param value a {@code MetricValue} to be added to the hash
   * @return the {@code Hasher}, to allow fluent-style usage
   */
  public static Hasher putMetricValue(Hasher h, MetricValue value) {
    Signing.putLabels(h, value.getLabelsMap());
    return h;
  }

  /**
   * Obtains the {@code HashCode} for the contents of {@code value}.
   *
   * @param value a {@code MetricValue} to be signed
   * @return the {@code HashCode} corresponding to {@code value}
   */
  public static HashCode sign(MetricValue value) {
    Hasher h = Hashing.md5().newHasher();
    return putMetricValue(h, value).hash();
  }

  /**
   * Merge {@code prior} with {@code latest}.
   *
   * If {@code kind} is {@code MetricKind.DELTA} then the result contains a combination of values in
   * prior and latest. For all other kinds, it's sufficient to return the metric with the latest end
   * time.
   *
   * @param kind the {@code MetricKind}
   * @param prior a {@code MetricValue} instance
   * @param latest a {@code MetricValue}, expected to be a later version of {@code prior}
   *
   * @return a new {@code MetricValue} that combines prior and latest depending on {@code kind}
   * @throws IllegalArgumentException if the {@code prior} and {@code latest} are have different
   *         types of value, or if the type is not mergeable
   */
  public static MetricValue merge(MetricKind kind, MetricValue prior, MetricValue latest) {
    if (prior.getValueCase() != latest.getValueCase()) {
      log.log(Level.WARNING, "Could not merge different types of metric: {0}, {1}",
          new Object[] {prior, latest});
      throw new IllegalArgumentException(MSG_CANNOT_MERGE_DIFFERENT_TYPES);
    }
    if (kind == MetricKind.DELTA) {
      Builder builder = latest.toBuilder();
      mergeTimestamps(builder, prior, latest);
      mergeValues(builder, prior, latest);
      return builder.build();
    } else if (Timestamps.COMPARATOR.compare(prior.getEndTime(), latest.getEndTime()) == -1) {
      return latest;
    } else {
      return prior;
    }
  }

  static void mergeValues(Builder builder, MetricValue prior, MetricValue latest) {
    switch (latest.getValueCase()) {
      case DOUBLE_VALUE:
        builder.setDoubleValue(prior.getDoubleValue() + latest.getDoubleValue());
        break;
      case DISTRIBUTION_VALUE:
        builder.setDistributionValue(
            Distributions.merge(prior.getDistributionValue(), latest.getDistributionValue()));
        break;
      case INT64_VALUE:
        builder.setInt64Value(prior.getInt64Value() + latest.getInt64Value());
        break;
      default:
        log.log(Level.WARNING, "Could not merge logs with unmergable metric types: {0}, {1}",
            new Object[] {prior, latest});
        throw new IllegalArgumentException(MSG_NOT_MERGABLE);
    }
  }

  private static void mergeTimestamps(Builder builder, MetricValue prior, MetricValue latest) {
    if (Timestamps.COMPARATOR.compare(prior.getEndTime(), latest.getEndTime()) > 0) {
      builder.setEndTime(prior.getEndTime());
    }
    if (Timestamps.COMPARATOR.compare(prior.getStartTime(), latest.getStartTime()) < 0) {
      builder.setStartTime(prior.getStartTime());
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy