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

com.spotify.autoscaler.client.StackdriverClient Maven / Gradle / Ivy

/*-
 * -\-\-
 * bigtable-autoscaler
 * --
 * Copyright (C) 2018 Spotify AB
 * --
 * 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.spotify.autoscaler.client;

import com.google.cloud.monitoring.v3.MetricServiceClient;
import com.google.monitoring.v3.ListTimeSeriesRequest;
import com.google.monitoring.v3.Point;
import com.google.monitoring.v3.ProjectName;
import com.google.monitoring.v3.TimeInterval;
import com.google.monitoring.v3.TimeSeries;
import com.google.monitoring.v3.TypedValue;
import com.google.protobuf.Timestamp;
import com.spotify.autoscaler.db.BigtableCluster;
import java.io.Closeable;
import java.io.IOException;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import javax.validation.constraints.NotNull;

public class StackdriverClient implements Closeable {

  private static final String CPU_METRIC =
      "metric.type=\"bigtable.googleapis.com/cluster/cpu_load\""
          + " AND resource.labels.instance=\"%s\" AND resource.labels.cluster=\"%s\"";

  private static final String DISK_USAGE_METRIC =
      "metric.type=\"bigtable.googleapis.com/cluster/storage_utilization\""
          + " AND resource.labels.instance=\"%s\" AND resource.labels.cluster=\"%s\"";

  private final MetricServiceClient metricServiceClient;

  public StackdriverClient() throws IOException {
    metricServiceClient = MetricServiceClient.create();
  }

  public Double getDiskUtilization(final BigtableCluster bigtableCluster, final Duration duration) {

    final MetricServiceClient.ListTimeSeriesPagedResponse response =
        metricServiceClient.listTimeSeries(
            ProjectName.of(bigtableCluster.projectId()),
            String.format(
                DISK_USAGE_METRIC, bigtableCluster.instanceId(), bigtableCluster.clusterId()),
            interval(duration),
            ListTimeSeriesRequest.TimeSeriesView.FULL);
    return maxValueFromPagedResponse(response, 0.0, TypedValue::getDoubleValue);
  }

  public Double getCpuLoad(final BigtableCluster bigtableCluster, final Duration duration) {
    final MetricServiceClient.ListTimeSeriesPagedResponse response =
        metricServiceClient.listTimeSeries(
            ProjectName.of(bigtableCluster.projectId()),
            String.format(CPU_METRIC, bigtableCluster.instanceId(), bigtableCluster.clusterId()),
            interval(duration),
            ListTimeSeriesRequest.TimeSeriesView.FULL);
    return maxValueFromPagedResponse(response, 0.0, TypedValue::getDoubleValue);
  }

  private > T maxValueFromPagedResponse(
      final MetricServiceClient.ListTimeSeriesPagedResponse response,
      final T initialMax,
      final Function converter) {
    T max = initialMax;
    for (final MetricServiceClient.ListTimeSeriesPage page : response.iteratePages()) {
      for (final TimeSeries ts : page.getValues()) {
        for (final Point p : ts.getPointsList()) {
          final T value = converter.apply(p.getValue());
          max = value.compareTo(max) > 0 ? value : max;
        }
      }
    }
    return max;
  }

  public static TimeInterval interval(final Duration duration) {
    return getTimeInterval(duration);
  }

  @NotNull
  private static TimeInterval getTimeInterval(final Duration duration) {
    final long currentTimeSeconds = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis());

    final Timestamp pastTimestamp =
        Timestamp.newBuilder().setSeconds(currentTimeSeconds - duration.getSeconds()).build();
    final Timestamp currentTimestamp =
        Timestamp.newBuilder().setSeconds(currentTimeSeconds).build();
    return TimeInterval.newBuilder()
        .setStartTime(pastTimestamp)
        .setEndTime(currentTimestamp)
        .build();
  }

  @Override
  public void close() throws IOException {
    try {
      metricServiceClient.close();
    } catch (final Exception e) {
      throw new RuntimeException(e);
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy