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

com.github.kristofa.brave.FlushingSpanCollector Maven / Gradle / Ivy

There is a newer version: 4.13.6
Show newest version
package com.github.kristofa.brave;

import com.github.kristofa.brave.internal.Nullable;
import com.twitter.zipkin.gen.Span;
import java.io.Closeable;
import java.io.Flushable;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;

import static java.util.concurrent.TimeUnit.SECONDS;

/**
 * Extend this class to offload the task of reporting spans to separate thread. By doing so, callers
 * are protected from latency or exceptions possible when exporting spans out of process.
 *
 * @deprecated replaced by {@link zipkin.reporter.AsyncReporter}
 */
@Deprecated
public abstract class FlushingSpanCollector implements SpanCollector, Flushable, Closeable {

  private final SpanCollectorMetricsHandler metrics;
  private final BlockingQueue pending = new LinkedBlockingQueue(1000);
  @Nullable // for testing
  private final Flusher flusher;

  /**
   * @param flushInterval in seconds. 0 implies spans are {@link #flush() flushed externally.
   */
  protected FlushingSpanCollector(SpanCollectorMetricsHandler metrics, int flushInterval) {
    this.metrics = metrics;
    this.flusher = flushInterval > 0 ? new Flusher(this, flushInterval, getClass().getSimpleName()) : null;
  }

  /**
   * Queues the span for collection, or drops it if the queue is full.
   *
   * @param span Span, should not be null.
   */
  @Override
  public void collect(Span span) {
    metrics.incrementAcceptedSpans(1);
    if (!pending.offer(span)) {
      metrics.incrementDroppedSpans(1);
    }
  }

  /**
   * Calling this will flush any pending spans to the transport on the current thread.
   */
  @Override
  public void flush() {
    if (pending.isEmpty()) return;
    List drained = new ArrayList(pending.size());
    pending.drainTo(drained);
    if (drained.isEmpty()) return;

    int spanCount = drained.size();
    try {
      reportSpans(drained);
    } catch (IOException e) {
      metrics.incrementDroppedSpans(spanCount);
    } catch (RuntimeException e) {
      metrics.incrementDroppedSpans(spanCount);
    }
  }

  /** Calls flush on a fixed interval */
  static final class Flusher implements Runnable {
    final Flushable flushable;
    final ScheduledExecutorService scheduler;

    Flusher(Flushable flushable, int flushInterval, final String threadPoolName) {
      this.flushable = flushable;
      this.scheduler = Executors.newSingleThreadScheduledExecutor(
          r -> new Thread(r, threadPoolName));
      this.scheduler.scheduleWithFixedDelay(this, 0, flushInterval, SECONDS);
    }

    @Override
    public void run() {
      try {
        flushable.flush();
      } catch (IOException ignored) {
      }
    }
  }

  /**
   * Reports a list of spans over the current transport.
   *
   * @throws IOException (or RuntimeException) when thrown, drop metrics will increment accordingly
   */
  protected abstract void reportSpans(List drained) throws IOException;

  @Override
  public void addDefaultAnnotation(String key, String value) {
    throw new UnsupportedOperationException();
  }

  /**
   * Requests a cease of delivery. There will be at most one in-flight send after this call.
   */
  @Override
  public void close() {
    if (flusher != null) flusher.scheduler.shutdown();
    // throw any outstanding spans on the floor
    int dropped = pending.drainTo(new LinkedList());
    metrics.incrementDroppedSpans(dropped);
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy