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

zipkin.storage.elasticsearch.ElasticsearchStorage Maven / Gradle / Ivy

There is a newer version: 1.5.1
Show newest version
/**
 * Copyright 2015-2016 The OpenZipkin 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 zipkin.storage.elasticsearch;

import com.google.common.annotations.VisibleForTesting;
import java.util.Collections;
import java.util.List;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.admin.indices.flush.FlushRequest;
import org.elasticsearch.action.bulk.BulkRequestBuilder;
import org.elasticsearch.client.Client;
import org.elasticsearch.cluster.health.ClusterHealthStatus;
import zipkin.DependencyLink;
import zipkin.internal.Util;
import zipkin.storage.guava.LazyGuavaStorageComponent;

import static com.google.common.base.Preconditions.checkState;
import static com.google.common.util.concurrent.Futures.getUnchecked;
import static zipkin.internal.Util.checkNotNull;

public final class ElasticsearchStorage
    extends LazyGuavaStorageComponent {

  /**
   * Internal flag that allows you read-your-writes consistency during tests. With Elasticsearch, it
   * is not sufficient to block on futures since the index also needs to be flushed.
   */
  @VisibleForTesting
  static boolean FLUSH_ON_WRITES;

  public static Builder builder() {
    return new Builder();
  }

  public static final class Builder {
    String cluster = "elasticsearch";
    List hosts = Collections.singletonList("localhost:9300");
    String index = "zipkin";

    /**
     * The elasticsearch cluster to connect to, defaults to "elasticsearch".
     */
    public Builder cluster(String cluster) {
      this.cluster = checkNotNull(cluster, "cluster");
      return this;
    }

    /**
     * A comma separated list of elasticsearch hostnodes to connect to, in host:port format. The
     * port should be the transport port, not the http port. Defaults to "localhost:9300".
     */
    public Builder hosts(List hosts) {
      this.hosts = checkNotNull(hosts, "hosts");
      return this;
    }

    /**
     * The index prefix to use when generating daily index names. Defaults to zipkin.
     */
    public Builder index(String index) {
      this.index = checkNotNull(index, "index");
      return this;
    }

    public ElasticsearchStorage build() {
      return new ElasticsearchStorage(this);
    }

    Builder() {
    }
  }

  private final LazyClient lazyClient;
  private final IndexNameFormatter indexNameFormatter;

  ElasticsearchStorage(Builder builder) {
    lazyClient = new LazyClient(builder);
    indexNameFormatter = new IndexNameFormatter(builder.index);
  }

  /** Lazy initializes or returns the client in use by this storage component. */
  public Client client() {
    return lazyClient.get();
  }

  @Override protected ElasticsearchSpanStore computeGuavaSpanStore() {
    return new ElasticsearchSpanStore(lazyClient.get(), indexNameFormatter);
  }

  @Override protected ElasticsearchSpanConsumer computeGuavaSpanConsumer() {
    return new ElasticsearchSpanConsumer(lazyClient.get(), indexNameFormatter);
  }

  @VisibleForTesting void writeDependencyLinks(List links, long timestampMillis) {
    long midnight = Util.midnightUTC(timestampMillis);
    BulkRequestBuilder request = lazyClient.get().prepareBulk();
    for (DependencyLink link : links) {
      request.add(lazyClient.get().prepareIndex(
          indexNameFormatter.indexNameForTimestamp(midnight),
          ElasticsearchConstants.DEPENDENCY_LINK)
          .setSource(
              "parent", link.parent,
              "child", link.child,
              "parent_child", link.parent + "|" + link.child,  // For aggregating callCount
              "callCount", link.callCount));
    }
    request.execute().actionGet();
    lazyClient.get().admin().indices().flush(new FlushRequest()).actionGet();
  }

  @VisibleForTesting void clear() {
    lazyClient.get().admin().indices().delete(new DeleteIndexRequest(indexNameFormatter.catchAll()))
        .actionGet();
    lazyClient.get().admin().indices().flush(new FlushRequest()).actionGet();
  }

  @Override public CheckResult check() {
    try {
      ClusterHealthResponse health = getUnchecked(lazyClient.get()
          .admin().cluster().prepareHealth(indexNameFormatter.catchAll()).execute());
      checkState(health.getStatus() != ClusterHealthStatus.RED, "Health status is RED");
    } catch (RuntimeException e) {
      return CheckResult.failed(e);
    }
    return CheckResult.OK;
  }

  @Override public void close() {
    lazyClient.close();
  }

  @Override public String toString() {
    return lazyClient.toString();
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy