zipkin2.reporter.brave.AsyncZipkinSpanHandler Maven / Gradle / Ivy
Show all versions of zipkin-reporter-brave Show documentation
/*
 * Copyright The OpenZipkin Authors
 * SPDX-License-Identifier: Apache-2.0
 */
package zipkin2.reporter.brave;
import brave.Tag;
import brave.handler.MutableSpan;
import brave.handler.SpanHandler;
import brave.propagation.TraceContext;
import java.io.Closeable;
import java.io.Flushable;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import zipkin2.reporter.BytesEncoder;
import zipkin2.reporter.BytesMessageSender;
import zipkin2.reporter.Encoding;
import zipkin2.reporter.Reporter;
import zipkin2.reporter.ReporterMetrics;
import zipkin2.reporter.Sender;
import zipkin2.reporter.internal.AsyncReporter;
/**
 * A {@link brave.handler.SpanHandler} that queues spans on {@link #end} to bundle and send as a
 * bulk Zipkin JSON V2 message. When the {@link
 * BytesMessageSender} is HTTP, the endpoint is usually "http://zipkinhost:9411/api/v2/spans".
 *
 * Example:
 * 
{@code
 * sender = URLConnectionSender.create("http://localhost:9411/api/v2/spans");
 * zipkinSpanHandler = AsyncZipkinSpanHandler.create(sender); // don't forget to close!
 * tracingBuilder.addSpanHandler(zipkinSpanHandler);
 * }
 *
 * @see ZipkinSpanHandler if you need to use a different format
 * @see brave.Tracing.Builder#addSpanHandler(SpanHandler)
 * @since 2.14
 */
public final class AsyncZipkinSpanHandler extends SpanHandler implements Closeable, Flushable {
  /** @deprecated Since 3.2, use {@link #create(BytesMessageSender)} */
  @Deprecated public static AsyncZipkinSpanHandler create(Sender sender) {
    return create((BytesMessageSender) sender);
  }
  /** @since 3.2 */
  public static AsyncZipkinSpanHandler create(BytesMessageSender sender) {
    return newBuilder(sender).build();
  }
  /** @deprecated Since 3.2, use {@link #newBuilder(BytesMessageSender)} */
  @Deprecated public static Builder newBuilder(Sender sender) {
    return newBuilder((BytesMessageSender) sender);
  }
  /** @since 3.2 */
  public static Builder newBuilder(BytesMessageSender sender) {
    if (sender == null) throw new NullPointerException("sender == null");
    return new Builder(sender);
  }
  /**
   * Allows this instance to be reconfigured, for example {@link ZipkinSpanHandler.Builder#alwaysReportSpans(boolean)}.
   *
   * Note: Call {@link #close()} if you no longer need this instance, as otherwise it
   * can leak resources.
   *
   * @since 2.15
   */
  public Builder toBuilder() {
    return new Builder(this);
  }
  /** @since 2.14 */
  public static final class Builder extends ZipkinSpanHandler.Builder {
    final AsyncReporter.Builder delegate;
    final Encoding encoding;
    Builder(AsyncZipkinSpanHandler handler) {
      this.delegate = ((AsyncReporter) handler.spanReporter).toBuilder();
      this.encoding = handler.encoding;
      this.alwaysReportSpans = handler.alwaysReportSpans;
      this.errorTag = handler.errorTag;
    }
    Builder(BytesMessageSender sender) {
      this.delegate = AsyncReporter.newBuilder(sender);
      this.encoding = sender.encoding();
    }
    /**
     * @see AsyncReporter.Builder#threadFactory(ThreadFactory)
     * @since 2.14
     */
    public Builder threadFactory(ThreadFactory threadFactory) {
      delegate.threadFactory(threadFactory);
      return this;
    }
    /**
     * @see AsyncReporter.Builder#metrics(ReporterMetrics)
     * @since 2.14
     */
    public Builder metrics(ReporterMetrics metrics) {
      delegate.metrics(metrics);
      return this;
    }
    /**
     * @see AsyncReporter.Builder#messageMaxBytes(int)
     * @since 2.14
     */
    public Builder messageMaxBytes(int messageMaxBytes) {
      delegate.messageMaxBytes(messageMaxBytes);
      return this;
    }
    /**
     * @see AsyncReporter.Builder#messageTimeout(long, TimeUnit)
     * @since 2.14
     */
    public Builder messageTimeout(long timeout, TimeUnit unit) {
      delegate.messageTimeout(timeout, unit);
      return this;
    }
    /**
     * @see AsyncReporter.Builder#closeTimeout(long, TimeUnit)
     * @since 2.14
     */
    public Builder closeTimeout(long timeout, TimeUnit unit) {
      delegate.closeTimeout(timeout, unit);
      return this;
    }
    /**
     * @see AsyncReporter.Builder#queuedMaxSpans(int)
     * @since 2.14
     */
    public Builder queuedMaxSpans(int queuedMaxSpans) {
      delegate.queuedMaxSpans(queuedMaxSpans);
      return this;
    }
    /**
     * Maximum backlog of span bytes reported vs sent. Disabled by default
     *
     * @deprecated This will be removed in version 4.0. Use {@link #queuedMaxSpans(int)} instead.
     */
    @Deprecated
    public Builder queuedMaxBytes(int queuedMaxBytes) {
      this.delegate.queuedMaxBytes(queuedMaxBytes);
      return this;
    }
    @Override public Builder errorTag(Tag errorTag) {
      return (Builder) super.errorTag(errorTag);
    }
    @Override public Builder alwaysReportSpans(boolean alwaysReportSpans) {
      return (Builder) super.alwaysReportSpans(alwaysReportSpans);
    }
    /**
     * Builds an async span handler that encodes zipkin spans according to the sender's encoding.
     */
    // AsyncZipkinSpanHandler not SpanHandler, so that Flushable and Closeable are accessible
    public AsyncZipkinSpanHandler build() {
      return build(MutableSpanBytesEncoder.create(encoding, errorTag));
    }
    /**
     * Builds an async span handler that encodes zipkin spans according to the encoder.
     *
     * Note: The input encoder must use the same error tag implementation as configured by
     * {@link #errorTag(Tag)}.
     *
     * @since 3.1
     */
    // AsyncZipkinSpanHandler not SpanHandler, so that Flushable and Closeable are accessible
    public AsyncZipkinSpanHandler build(BytesEncoder encoder) {
      if (encoder == null) throw new NullPointerException("encoder == null");
      return new AsyncZipkinSpanHandler(delegate.build(encoder), this);
    }
  }
  final Reporter spanReporter;
  final Encoding encoding;
  final Tag errorTag; // for toBuilder()
  final boolean alwaysReportSpans;
  AsyncZipkinSpanHandler(AsyncReporter spanReporter, Builder builder) {
    this.spanReporter = spanReporter;
    this.encoding = builder.encoding;
    this.errorTag = builder.errorTag;
    this.alwaysReportSpans = builder.alwaysReportSpans;
  }
  @Override public void flush() {
    ((AsyncReporter) spanReporter).flush();
  }
  /**
   * Implementations that throw exceptions on close have bugs. This may result in log warnings,
   * though.
   *
   * @since 2.15
   */
  @Override public void close() {
    ((AsyncReporter) spanReporter).close();
  }
  @Override public boolean end(TraceContext context, MutableSpan span, Cause cause) {
    if (!alwaysReportSpans && !Boolean.TRUE.equals(context.sampled())) return true;
    spanReporter.report(span);
    return true;
  }
  @Override public String toString() {
    return spanReporter.toString();
  }
  /**
   * Overridden to avoid duplicates when added via {@link brave.Tracing.Builder#addSpanHandler(SpanHandler)}
   */
  @Override public boolean equals(Object o) {
    if (o == this) return true;
    if (!(o instanceof AsyncZipkinSpanHandler)) return false;
    return spanReporter.equals(((AsyncZipkinSpanHandler) o).spanReporter);
  }
  /**
   * Overridden to avoid duplicates when added via {@link brave.Tracing.Builder#addSpanHandler(SpanHandler)}
   */
  @Override public int hashCode() {
    return spanReporter.hashCode();
  }
}