<commit_before>/*
 * Copyright 2017, OpenCensus Authors
 *
 * 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 io.opencensus.exporter.stats.stackdriver;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;

import com.google.api.MonitoredResource;
import com.google.api.gax.core.FixedCredentialsProvider;
import com.google.auth.Credentials;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.cloud.ServiceOptions;
import com.google.cloud.monitoring.v3.MetricServiceClient;
import com.google.cloud.monitoring.v3.MetricServiceSettings;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.util.concurrent.MoreExecutors;
import io.opencensus.common.Duration;
import io.opencensus.stats.Stats;
import io.opencensus.stats.ViewManager;
import java.io.IOException;
import java.util.concurrent.ThreadFactory;
import javax.annotation.Nullable;
import javax.annotation.concurrent.GuardedBy;

/**
 * Exporter to Stackdriver Monitoring Client API v3.
 *
 * <p>Example of usage on Google Cloud VMs:
 *
 * <pre><code>
 *   public static void main(String[] args) {
 *     StackdriverStatsExporter.createAndRegister(
 *         StackdriverStatsConfiguration
 *             .builder()
 *             .setProjectId("MyStackdriverProjectId")
 *             .setExportInterval(Duration.fromMillis(100000))
 *             .build());
 *     ... // Do work.
 *   }
 * </code></pre>
 */
public final class StackdriverStatsExporter {

  private static final Object monitor = new Object();

  private final Thread workerThread;

  @GuardedBy("monitor")
  private static StackdriverStatsExporter exporter = null;

  private static final Duration ZERO = Duration.create(0, 0);

  @VisibleForTesting static final Duration DEFAULT_INTERVAL = Duration.create(60, 0);

  @VisibleForTesting
  static final MonitoredResource DEFAULT_RESOURCE =
      MonitoredResource.newBuilder().setType("global").build();

  @VisibleForTesting
  StackdriverStatsExporter(
      String projectId,
      MetricServiceClient metricServiceClient,
      Duration exportInterval,
      ViewManager viewManager,
      MonitoredResource monitoredResource) {
    checkArgument(exportInterval.compareTo(ZERO) > 0, "Duration must be positive");
    StackdriverExporterWorker worker =
        new StackdriverExporterWorker(
            projectId, metricServiceClient, exportInterval, viewManager, monitoredResource);
    this.workerThread = new DaemonThreadFactory().newThread(worker);
  }

  /**
   * Creates a StackdriverStatsExporter for an explicit project ID and using explicit credentials,
   * with default Monitored Resource.
   *
   * <p>Only one Stackdriver exporter can be created.
   *
   * @param credentials a credentials used to authenticate API calls.
   * @param projectId the cloud project id.
   * @param exportInterval the interval between pushing stats to StackDriver.
   * @throws IllegalStateException if a Stackdriver exporter already exists.
   * @deprecated in favor of {@link #createAndRegister(StackdriverStatsConfiguration)}.
   */
  @Deprecated
  public static void createAndRegisterWithCredentialsAndProjectId(
      Credentials credentials, String projectId, Duration exportInterval) throws IOException {
    checkNotNull(credentials, "credentials");
    checkNotNull(projectId, "projectId");
    checkNotNull(exportInterval, "exportInterval");
    createInternal(credentials, projectId, exportInterval, null);
  }

  /**
   * Creates a Stackdriver Stats exporter for an explicit project ID, with default Monitored
   * Resource.
   *
   * <p>Only one Stackdriver exporter can be created.
   *
   * <p>This uses the default application credentials. See {@link
   * GoogleCredentials#getApplicationDefault}.
   *
   * <p>This is equivalent with:
   *
   * <pre>{@code
   * StackdriverStatsExporter.createWithCredentialsAndProjectId(
   *     GoogleCredentials.getApplicationDefault(), projectId);
   * }</pre>
   *
   * @param projectId the cloud project id.
   * @param exportInterval the interval between pushing stats to StackDriver.
   * @throws IllegalStateException if a Stackdriver exporter is already created.
   * @deprecated in favor of {@link #createAndRegister(StackdriverStatsConfiguration)}.
   */
  @Deprecated
  public static void createAndRegisterWithProjectId(String projectId, Duration exportInterval)
      throws IOException {
    checkNotNull(projectId, "projectId");
    checkNotNull(exportInterval, "exportInterval");
    createInternal(null, projectId, exportInterval, null);
  }

  /**
   * Creates a Stackdriver Stats exporter with a {@link StackdriverStatsConfiguration}.
   *
   * <p>Only one Stackdriver exporter can be created.
   *
   * <p>If {@code credentials} of the configuration is not set, the exporter will use the default
   * application credentials. See {@link GoogleCredentials#getApplicationDefault}.
   *
   * <p>If {@code projectId} of the configuration is not set, the exporter will use the default
   * project ID configured. See {@link ServiceOptions#getDefaultProjectId}.
   *
   * <p>If {@code exportInterval} of the configuration is not set, the exporter will use the default
   * interval of one minute.
   *
   * <p>If {@code monitoredResources} of the configuration is not set, the exporter will use the
   * default resource with type global and no labels. In addition, please refer to
   * cloud.google.com/monitoring/custom-metrics/creating-metrics#which-resource for a list of valid
   * {@code MonitoredResource}s.
   *
   * @param configuration the {@code StackdriverStatsConfiguration}.
   * @throws IllegalStateException if a Stackdriver exporter is already created.
   */
  public static void createAndRegister(StackdriverStatsConfiguration configuration)
      throws IOException {
    checkNotNull(configuration, "configuration");
    createInternal(
        configuration.getCredentials(),
        configuration.getProjectId(),
        configuration.getExportInterval(),
        configuration.getMonitoredResource());
  }

  /**
   * Creates a Stackdriver Stats exporter with default Monitored Resource.
   *
   * <p>Only one Stackdriver exporter can be created.
   *
   * <p>This uses the default application credentials. See {@link<commit_msg>Add a convenient method to create Stackdriver exporter with default settings (#907)<commit_after>/*
 * Copyright 2017, OpenCensus Authors
 *
 * 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 io.opencensus.exporter.stats.stackdriver;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;

import com.google.api.MonitoredResource;
import com.google.api.gax.core.FixedCredentialsProvider;
import com.google.auth.Credentials;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.cloud.ServiceOptions;
import com.google.cloud.monitoring.v3.MetricServiceClient;
import com.google.cloud.monitoring.v3.MetricServiceSettings;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.util.concurrent.MoreExecutors;
import io.opencensus.common.Duration;
import io.opencensus.stats.Stats;
import io.opencensus.stats.ViewManager;
import java.io.IOException;
import java.util.concurrent.ThreadFactory;
import javax.annotation.Nullable;
import javax.annotation.concurrent.GuardedBy;

/**
 * Exporter to Stackdriver Monitoring Client API v3.
 *
 * <p>Example of usage on Google Cloud VMs:
 *
 * <pre><code>
 *   public static void main(String[] args) {
 *     StackdriverStatsExporter.createAndRegister(
 *         StackdriverStatsConfiguration
 *             .builder()
 *             .setProjectId("MyStackdriverProjectId")
 *             .setExportInterval(Duration.fromMillis(100000))
 *             .build());
 *     ... // Do work.
 *   }
 * </code></pre>
 */
public final class StackdriverStatsExporter {

  private static final Object monitor = new Object();

  private final Thread workerThread;

  @GuardedBy("monitor")
  private static StackdriverStatsExporter exporter = null;

  private static final Duration ZERO = Duration.create(0, 0);

  @VisibleForTesting static final Duration DEFAULT_INTERVAL = Duration.create(60, 0);

  @VisibleForTesting
  static final MonitoredResource DEFAULT_RESOURCE =
      MonitoredResource.newBuilder().setType("global").build();

  @VisibleForTesting
  StackdriverStatsExporter(
      String projectId,
      MetricServiceClient metricServiceClient,
      Duration exportInterval,
      ViewManager viewManager,
      MonitoredResource monitoredResource) {
    checkArgument(exportInterval.compareTo(ZERO) > 0, "Duration must be positive");
    StackdriverExporterWorker worker =
        new StackdriverExporterWorker(
            projectId, metricServiceClient, exportInterval, viewManager, monitoredResource);
    this.workerThread = new DaemonThreadFactory().newThread(worker);
  }

  /**
   * Creates a StackdriverStatsExporter for an explicit project ID and using explicit credentials,
   * with default Monitored Resource.
   *
   * <p>Only one Stackdriver exporter can be created.
   *
   * @param credentials a credentials used to authenticate API calls.
   * @param projectId the cloud project id.
   * @param exportInterval the interval between pushing stats to StackDriver.
   * @throws IllegalStateException if a Stackdriver exporter already exists.
   * @deprecated in favor of {@link #createAndRegister(StackdriverStatsConfiguration)}.
   */
  @Deprecated
  public static void createAndRegisterWithCredentialsAndProjectId(
      Credentials credentials, String projectId, Duration exportInterval) throws IOException {
    checkNotNull(credentials, "credentials");
    checkNotNull(projectId, "projectId");
    checkNotNull(exportInterval, "exportInterval");
    createInternal(credentials, projectId, exportInterval, null);
  }

  /**
   * Creates a Stackdriver Stats exporter for an explicit project ID, with default Monitored
   * Resource.
   *
   * <p>Only one Stackdriver exporter can be created.
   *
   * <p>This uses the default application credentials. See {@link
   * GoogleCredentials#getApplicationDefault}.
   *
   * <p>This is equivalent with:
   *
   * <pre>{@code
   * StackdriverStatsExporter.createWithCredentialsAndProjectId(
   *     GoogleCredentials.getApplicationDefault(), projectId);
   * }</pre>
   *
   * @param projectId the cloud project id.
   * @param exportInterval the interval between pushing stats to StackDriver.
   * @throws IllegalStateException if a Stackdriver exporter is already created.
   * @deprecated in favor of {@link #createAndRegister(StackdriverStatsConfiguration)}.
   */
  @Deprecated
  public static void createAndRegisterWithProjectId(String projectId, Duration exportInterval)
      throws IOException {
    checkNotNull(projectId, "projectId");
    checkNotNull(exportInterval, "exportInterval");
    createInternal(null, projectId, exportInterval, null);
  }

  /**
   * Creates a Stackdriver Stats exporter with a {@link StackdriverStatsConfiguration}.
   *
   * <p>Only one Stackdriver exporter can be created.
   *
   * <p>If {@code credentials} of the configuration is not set, the exporter will use the default
   * application credentials. See {@link GoogleCredentials#getApplicationDefault}.
   *
   * <p>If {@code projectId} of the configuration is not set, the exporter will use the default
   * project ID configured. See {@link ServiceOptions#getDefaultProjectId}.
   *
   * <p>If {@code exportInterval} of the configuration is not set, the exporter will use the default
   * interval of one minute.
   *
   * <p>If {@code monitoredResources} of the configuration is not set, the exporter will use the
   * default resource with type global and no labels. In addition, please refer to
   * cloud.google.com/monitoring/custom-metrics/creating-metrics#which-resource for a list of valid
   * {@code MonitoredResource}s.
   *
   * @param configuration the {@code StackdriverStatsConfiguration}.
   * @throws IllegalStateException if a Stackdriver exporter is already created.
   * @since 0.11.0
   */
  public static void createAndRegister(StackdriverStatsConfiguration configuration)
      throws IOException {
    checkNotNull(configuration, "configuration");
    createInternal(
        configuration.getCredentials(),
        configuration.getProjectId(),
        configuration.getExportInterval(),
        configuration.getMonitoredResource());
  }

  /**
   * Creates a Stackdriver Stats exporter with default settings.
   *
   * <p>Only one Stackdriver exporter can be created.
   *
   * <p>This is equivalent with:
   *
   * <pre>{@code
   * StackdriverStatsExporter.createAndRegister(StackdriverStatsConfiguration.builder().build());
   * }</pre>
   *
   * <p>This method uses the default application credentials. See {@link
   * GoogleCredentials#getApplicationDefault}.
   *
   * <p>This method uses the default project ID configured. See {@link
   * ServiceOptions#getDefaultProjectId}.
   *
   * <p>This method uses the default interval of one minute.
   *
   * <p>This method uses the default resource with type global and no labels.
   *
   * @throws IllegalStateException if a Stackdriver exporter is already created.
   * @since 0.11.0
   */
  public static void createAndRegister() throws IOException {
    createInternal(null, null, null, null);
  }

  /**
   * Creates a Stackdriver Stats exporter with default Monitored Resource.
   *
   * <p>Only one Stackdriver exporter can be created.
   *
   * <p>This uses the default application credentials. See {@link
{'fraction_non_alphanumeric': 0.08487884120752674, 'fraction_numerical': 0.003993502098280763, 'mean_word_length': 4.11954261954262, 'pattern_counts': {'":': 0, '<': 47, '<?xml version=': 0, '>': 49, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3027032', 'n_tokens_mistral': 3894, 'n_tokens_neox': 3804, 'n_words': 1217}