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

brave.opentracing.BraveSpan Maven / Gradle / Ivy

There is a newer version: 1.0.1
Show newest version
/*
 * Copyright 2016-2020 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 brave.opentracing;

import brave.Span.Kind;
import brave.Tracer;
import brave.baggage.BaggageField;
import brave.baggage.BaggagePropagation;
import brave.internal.Nullable;
import io.opentracing.Span;
import io.opentracing.tag.Tags;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

/**
 * Holds the {@linkplain brave.Span} used by the underlying {@linkplain brave.Tracer}.
 *
 * 

This type also includes hooks to integrate with the underlying {@linkplain brave.Tracer}. Ex * you can access the underlying span with {@link #unwrap} * *

Operations to add data to the span are ignored once {@link #finish()} or {@link * #finish(long)} are called. */ public final class BraveSpan implements Span { private final Tracer tracer; volatile BraveSpanContext context; /** Prevents late adding data to a span */ volatile boolean finishCalled; /** Reference invalidated when sampling priority set to 0, which can happen on any thread */ volatile brave.Span delegate; volatile String remoteIpV4, remoteIpV6; volatile int remotePort; // tracer is only needed because the sampling.priority flag is used as a sampling api BraveSpan(brave.Tracer tracer, brave.Span delegate) { this.tracer = tracer; if (delegate == null) throw new NullPointerException("delegate == null"); this.delegate = delegate; this.context = BraveSpanContext.create(delegate.context()); } /** * Returns wrapped {@linkplain brave.Span} */ public final brave.Span unwrap() { return delegate; } @Override public BraveSpanContext context() { return context; } @Override public BraveSpan setTag(String key, String value) { if (finishCalled) return this; if (trySetPeer(delegate, key, value)) return this; Kind kind = trySetKind(key, value); if (kind != null) { delegate.kind(kind); context.kind = kind; return this; } delegate.tag(key, value); return this; } @Override public BraveSpan setTag(String key, boolean value) { if (finishCalled) return this; if (Tags.ERROR.getKey().equals(key) && !value) return this; return setTag(key, Boolean.toString(value)); } /** * Note:If the key is {@linkplain Tags#SAMPLING_PRIORITY} and the value is zero, the * current span will be abandoned and future references to the {@link #context()} will be * unsampled. This does not affect the active span, nor does it affect any equivalent instances of * this object. This is a best efforts means to handle late sampling decisions. */ @Override public BraveSpan setTag(String key, Number value) { if (finishCalled) return this; if (trySetPeer(key, value)) return this; // handle late sampling decision if (Tags.SAMPLING_PRIORITY.getKey().equals(key) && value.intValue() == 0) { delegate.abandon(); // convert the span to no-op Kind kind = context.kind; delegate = tracer.toSpan(delegate.context().toBuilder().sampled(false).build()); context = BraveSpanContext.create(delegate.context()); context.kind = kind; } return setTag(key, value.toString()); } @Override public BraveSpan setTag(io.opentracing.tag.Tag tag, T value) { // Strange there's a new api only to dispatch something that can be done as easily directly // eg instead of tag.set(span, value) this allows span.setTag(tag, value) (3 more characters!) // Would be nice to see documentation clarify why this was important enough to break api over. tag.set(this, value); return this; } @Override public BraveSpan log(Map fields) { if (finishCalled) return this; if (fields.isEmpty()) return this; return log(toAnnotation(fields)); } @Override public BraveSpan log(long timestampMicroseconds, Map fields) { if (finishCalled) return this; if (fields.isEmpty()) return this; // in real life, do like zipkin-go-opentracing: "key1=value1 key2=value2" return log(timestampMicroseconds, toAnnotation(fields)); } @Override public BraveSpan log(String event) { if (finishCalled) return this; delegate.annotate(event); return this; } @Override public BraveSpan log(long timestampMicroseconds, String event) { if (finishCalled) return this; delegate.annotate(timestampMicroseconds, event); return this; } /** This is a NOOP unless {@link BaggagePropagation} is in use */ @Override public BraveSpan setBaggageItem(String key, String value) { BaggageField field = BaggageField.getByName(delegate.context(), key); if (field == null) return this; field.updateValue(delegate.context(), value); return this; } /** Returns null unless {@link BaggagePropagation} is in use */ @Override public String getBaggageItem(String key) { BaggageField field = BaggageField.getByName(delegate.context(), key); if (field == null) return null; return field.getValue(delegate.context()); } @Override public BraveSpan setOperationName(String operationName) { if (finishCalled) return this; delegate.name(operationName); return this; } @Override public void finish() { if (finishCalled) return; finishCalled = true; trySetRemoteIpAndPort(); delegate.finish(); } @Override public void finish(long finishMicros) { if (finishCalled) return; finishCalled = true; trySetRemoteIpAndPort(); delegate.finish(finishMicros); } /** * Converts a map to a string of form: "key1=value1 key2=value2" */ static String toAnnotation(Map fields) { // special-case the "event" field which is similar to the semantics of a zipkin annotation Object event = fields.get("event"); if (event != null && fields.size() == 1) return event.toString(); return joinOnEqualsSpace(fields); } static String joinOnEqualsSpace(Map fields) { if (fields.isEmpty()) return ""; StringBuilder result = new StringBuilder(); for (Iterator> i = fields.entrySet().iterator(); i.hasNext(); ) { Map.Entry next = i.next(); result.append(next.getKey()).append('=').append(next.getValue()); if (i.hasNext()) result.append(' '); } return result.toString(); } @Nullable static Kind trySetKind(String key, String value) { if (!Tags.SPAN_KIND.getKey().equals(key)) return null; Kind kind; if (Tags.SPAN_KIND_CLIENT.equals(value)) { kind = Kind.CLIENT; } else if (Tags.SPAN_KIND_SERVER.equals(value)) { kind = Kind.SERVER; } else if (Tags.SPAN_KIND_PRODUCER.equals(value)) { kind = Kind.PRODUCER; } else if (Tags.SPAN_KIND_CONSUMER.equals(value)) { kind = Kind.CONSUMER; } else { return null; } return kind; } boolean trySetPeer(brave.Span span, String key, String value) { if (Tags.PEER_SERVICE.getKey().equals(key)) { span.remoteServiceName(value); } else if (Tags.PEER_HOST_IPV4.getKey().equals(key)) { remoteIpV4 = value; } else if (Tags.PEER_HOST_IPV6.getKey().equals(key)) { remoteIpV6 = value; } else { return false; } return true; } boolean trySetPeer(String key, Number value) { if (Tags.PEER_HOST_IPV4.getKey().equals(key)) { int ipv4 = value.intValue(); remoteIpV4 = new StringBuilder() .append(ipv4 >> 24 & 0xff).append('.') .append(ipv4 >> 16 & 0xff).append('.') .append(ipv4 >> 8 & 0xff).append('.') .append(ipv4 & 0xff).toString(); } else if (Tags.PEER_PORT.getKey().equals(key)) { remotePort = value.intValue(); } else { return false; } return true; } void trySetRemoteIpAndPort() { if (remoteIpV4 != null) delegate.remoteIpAndPort(remoteIpV4, remotePort); if (remoteIpV6 != null) delegate.remoteIpAndPort(remoteIpV6, remotePort); } @Override public String toString() { return context.toString(); } @Override public final boolean equals(Object o) { if (o == this) return true; if (!(o instanceof BraveSpan)) return false; return context.equals(((BraveSpan) o).context); } @Override public final int hashCode() { return context.hashCode(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy