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

com.github.kristofa.brave.scribe.ScribeSpanCollector Maven / Gradle / Ivy

package com.github.kristofa.brave.scribe;

import java.io.Closeable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.github.kristofa.brave.SpanCollectorMetricsHandler;
import com.github.kristofa.brave.SpanCollector;

import org.apache.thrift.TException;

import com.twitter.zipkin.gen.BinaryAnnotation;
import com.twitter.zipkin.gen.Span;

import static com.github.kristofa.brave.internal.Util.checkNotBlank;
import static com.github.kristofa.brave.internal.Util.checkNotNull;

/**
 * Sends spans to Scribe or any compatible service. This includes
 * the original Zipkin Collector Service which implements the Scribe interface.
 * 

* This SpanCollector is implemented so it puts spans on a queue which are processed by a separate thread. In this way we are * submitting spans asynchronously and we should have minimal overhead on application performance. *

* * @author kristof */ public class ScribeSpanCollector implements SpanCollector, Closeable { private static final String UTF_8 = "UTF-8"; private static final Logger LOGGER = Logger.getLogger(ScribeSpanCollector.class.getName()); private final BlockingQueue spanQueue; private final ExecutorService executorService; private final List spanProcessingThreads = new ArrayList<>(); private final List clientProviders = new ArrayList<>(); private final List> futures = new ArrayList<>(); private final Set defaultAnnotations = new HashSet<>(); private final SpanCollectorMetricsHandler metricsHandler; /** * Create a new instance with default queue size (= {@link ScribeSpanCollectorParams#DEFAULT_QUEUE_SIZE}) and default * batch size (= {@link ScribeSpanCollectorParams#DEFAULT_BATCH_SIZE}). * * @param host Host * @param port Port */ public ScribeSpanCollector(final String host, final int port) { this(host, port, new ScribeSpanCollectorParams()); } /** * Create a new instance. * * @param host Host for zipkin collector. * @param port Port for zipkin collector. * @param params Zipkin Span Collector parameters. */ public ScribeSpanCollector(final String host, final int port, final ScribeSpanCollectorParams params) { checkNotBlank(host, "Null or empty host"); checkNotNull(params, "Null params"); metricsHandler = params.getMetricsHandler(); spanQueue = new ArrayBlockingQueue(params.getQueueSize()); executorService = Executors.newFixedThreadPool(params.getNrOfThreads()); for (int i = 1; i <= params.getNrOfThreads(); i++) { // Creating a client provider for every spanProcessingThread. ScribeClientProvider clientProvider = createZipkinCollectorClientProvider(host, port, params); final SpanProcessingThread spanProcessingThread = new SpanProcessingThread(spanQueue, clientProvider, params.getBatchSize(), metricsHandler); spanProcessingThreads.add(spanProcessingThread); clientProviders.add(clientProvider); futures.add(executorService.submit(spanProcessingThread)); } } private ScribeClientProvider createZipkinCollectorClientProvider(String zipkinCollectorHost, int zipkinCollectorPort, ScribeSpanCollectorParams params) { ScribeClientProvider clientProvider = new ScribeClientProvider(zipkinCollectorHost, zipkinCollectorPort, params.getSocketTimeout()); try { clientProvider.setup(); } catch (final TException e) { if (params.failOnSetup()) { throw new IllegalStateException(e); } else { LOGGER.log(Level.WARNING, "Connection could not be established during setup.", e); } } return clientProvider; } /** * {@inheritDoc} */ @Override public void collect(final Span span) { metricsHandler.incrementAcceptedSpans(1); final long start = System.currentTimeMillis(); if (!defaultAnnotations.isEmpty()) { for (final BinaryAnnotation ba : defaultAnnotations) { span.addToBinary_annotations(ba); } } final boolean offer = spanQueue.offer(span); if (!offer) { LOGGER.warning("Queue rejected Span, span not submitted: "+ span); metricsHandler.incrementDroppedSpans(1); } else { final long end = System.currentTimeMillis(); if (LOGGER.isLoggable(Level.FINE)) { LOGGER.fine("Adding span to queue took " + (end - start) + "ms."); } } } /** * {@inheritDoc} */ @Override public void addDefaultAnnotation(final String key, final String value) { defaultAnnotations.add(BinaryAnnotation.create(key, value, null)); } /** * {@inheritDoc} */ @Override public void close() { LOGGER.info("Stopping SpanProcessingThread."); for (final SpanProcessingThread thread : spanProcessingThreads) { thread.stop(); } for (final Future future : futures) { try { final Integer spansProcessed = future.get(); LOGGER.info("SpanProcessingThread processed " + spansProcessed + "spans."); } catch (final Exception e) { LOGGER.log(Level.WARNING, "Exception when getting result of SpanProcessingThread.", e); } } for(final ScribeClientProvider clientProvider : clientProviders) { clientProvider.close(); } executorService.shutdown(); metricsHandler.incrementDroppedSpans(spanQueue.size()); LOGGER.info("ScribeSpanCollector closed."); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy