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

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

package com.github.kristofa.brave;

import com.github.kristofa.brave.internal.Nullable;
import com.twitter.zipkin.gen.Annotation;
import com.twitter.zipkin.gen.BinaryAnnotation;
import com.twitter.zipkin.gen.Endpoint;
import com.twitter.zipkin.gen.Span;

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

/**
 * Used to submit application specific annotations.
 *
 * @author kristof
 */
public abstract class AnnotationSubmitter {

    /**
     * This interface is used to make the implementation to AnnotationSubmitter.currentTimeMicroseconds() contextual.
     * The clock is defined by the subclass's implementation of the `clock()` method.
     * A DefaultClock implementation is provided that simply returns `System.currentTimeMillis() * 1000`.
     */
    public interface Clock {
        /**
         * Epoch microseconds used for {@link zipkin.Span#timestamp} and {@link zipkin.Annotation#timestamp}.
         *
         * 

This should use the most precise value possible. For example, {@code gettimeofday} or multiplying * {@link System#currentTimeMillis} by 1000. * *

See Instrumenting a service for more. */ long currentTimeMicroseconds(); } static AnnotationSubmitter create(SpanAndEndpoint spanAndEndpoint) { return new AnnotationSubmitterImpl(spanAndEndpoint, DefaultClock.INSTANCE); } public static AnnotationSubmitter create(SpanAndEndpoint spanAndEndpoint, Clock clock) { return new AnnotationSubmitterImpl(spanAndEndpoint, clock); } abstract SpanAndEndpoint spanAndEndpoint(); /** The implementation of Clock to use. * See {@link com.github.kristofa.brave.AnnotationSubmitter#currentTimeMicroseconds} * and {@link com.github.kristofa.brave.AnnotationSubmitter.Clock} **/ abstract Clock clock(); /** * Associates an event that explains latency with the current system time. * * @param value A short tag indicating the event, like "finagle.retry" */ public void submitAnnotation(String value) { Span span = spanAndEndpoint().span(); if (span != null) { Annotation annotation = Annotation.create( currentTimeMicroseconds(startTick(span)), value, spanAndEndpoint().endpoint() ); addAnnotation(span, annotation); } } /** * Associates an event that explains latency with a timestamp. * *

This is an alternative to {@link #submitAnnotation(String)}, when * you have a timestamp more precise or accurate than {@link System#currentTimeMillis()}. * * @param value A short tag indicating the event, like "finagle.retry" * @param timestamp microseconds from epoch */ public void submitAnnotation(String value, long timestamp) { Span span = spanAndEndpoint().span(); if (span != null) { Annotation annotation = Annotation.create( timestamp, value, spanAndEndpoint().endpoint() ); addAnnotation(span, annotation); } } /** This adds an annotation that corresponds with {@link Span#getTimestamp()} */ void submitStartAnnotation(String annotationName) { Span span = spanAndEndpoint().span(); if (span != null) { Annotation annotation = Annotation.create( currentTimeMicroseconds(null), annotationName, spanAndEndpoint().endpoint() ); synchronized (span) { span.setTimestamp(annotation.timestamp); span.addToAnnotations(annotation); span.startTick = System.nanoTime(); // embezzle start tick into an internal field. } } } /** * This adds an annotation that corresponds with {@link Span#getDuration()}, and sends the span * for collection. * * @return true if a span was sent for collection. */ boolean submitEndAnnotation(String annotationName, SpanCollector spanCollector) { Span span = spanAndEndpoint().span(); if (span == null) { return false; } Long startTimestamp; Long startTick; synchronized (span) { startTimestamp = span.getTimestamp(); startTick = span.startTick; } Long endTimestamp; Long duration = null; if (startTick != null) { long endTick = System.nanoTime(); duration = Math.max(1L, (endTick - startTick) / 1000L); endTimestamp = startTimestamp + duration; } else { endTimestamp = currentTimeMicroseconds(null); if (startTimestamp != null) { duration = Math.max(1L, endTimestamp - startTimestamp); } } Annotation annotation = Annotation.create( endTimestamp, annotationName, spanAndEndpoint().endpoint() ); synchronized (span) { span.addToAnnotations(annotation); if (startTimestamp != null) { span.setDuration(duration); } } spanCollector.collect(span); return true; } /** * Internal api for submitting an address. Until a naming function is added, this coerces null * {@code serviceName} to "unknown", as that's zipkin's convention. */ void submitAddress(String key, Endpoint endpoint) { Span span = spanAndEndpoint().span(); if (span != null) { if (endpoint.service_name == null) { endpoint = endpoint.toBuilder().serviceName("unknown").build(); } BinaryAnnotation ba = BinaryAnnotation.address(key, endpoint); addBinaryAnnotation(span, ba); } } /** * Binary annotations are tags applied to a Span to give it context. For * example, a key "your_app.version" would let you lookup spans by version. * * @param key Name used to lookup spans, such as "your_app.version" * @param value String value, should not be null. */ public void submitBinaryAnnotation(String key, String value) { Span span = spanAndEndpoint().span(); if (span != null) { BinaryAnnotation ba = BinaryAnnotation.create(key, value, spanAndEndpoint().endpoint()); addBinaryAnnotation(span, ba); } } /** * Submits a binary (key/value) annotation with int value. * * @param key Key, should not be blank. * @param value Integer value. */ public void submitBinaryAnnotation(String key, int value) { // Zipkin v1 UI and query only support String annotations. submitBinaryAnnotation(key, String.valueOf(value)); } long currentTimeMicroseconds(@Nullable Long startTick) { return startTick != null ? (System.nanoTime() - startTick) / 1000 : clock().currentTimeMicroseconds(); } private void addAnnotation(Span span, Annotation annotation) { synchronized (span) { span.addToAnnotations(annotation); } } private void addBinaryAnnotation(Span span, BinaryAnnotation ba) { synchronized (span) { span.addToBinary_annotations(ba); } } AnnotationSubmitter() { } private static final class AnnotationSubmitterImpl extends AnnotationSubmitter { private final SpanAndEndpoint spanAndEndpoint; private final Clock clock; private AnnotationSubmitterImpl(SpanAndEndpoint spanAndEndpoint, Clock clock) { this.spanAndEndpoint = checkNotNull(spanAndEndpoint, "Null spanAndEndpoint"); this.clock = clock; } @Override SpanAndEndpoint spanAndEndpoint() { return spanAndEndpoint; } @Override protected Clock clock() { return clock; } } static final class DefaultClock implements Clock { static final Clock INSTANCE = new DefaultClock(); private DefaultClock() {} @Override public long currentTimeMicroseconds() { return System.currentTimeMillis() * 1000; } } Long startTick(Span span) { synchronized (span) { return span.startTick; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy