io.jaegertracing.internal.JaegerSpan Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jaeger-core Show documentation
Show all versions of jaeger-core Show documentation
Jaeger Java bindings for OpenTracing API
/*
* Copyright (c) 2018, The Jaeger Authors
* Copyright (c) 2016, Uber Technologies, Inc
*
* 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 io.jaegertracing.internal;
import io.opentracing.Span;
import io.opentracing.log.Fields;
import io.opentracing.tag.Tags;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
/**
* Represents a Span as seen from Jaeger's perspective. Builds on OpenTracing's {@link Span}, adding properties that
* are not part of the standard.
*
* Should be used wisely by instrumented applications: always prefer OpenTracing's approach when available.
*/
@Slf4j
public class JaegerSpan implements Span {
private final JaegerTracer tracer;
private final long startTimeMicroseconds;
private final long startTimeNanoTicks;
private final boolean computeDurationViaNanoTicks;
private final Map tags;
private long durationMicroseconds; // span durationMicroseconds
private String operationName;
private final List references;
private JaegerSpanContext context;
private List logs;
private boolean finished = false; // to prevent the same span from getting reported multiple times
protected JaegerSpan(
JaegerTracer tracer,
String operationName,
JaegerSpanContext context,
long startTimeMicroseconds,
long startTimeNanoTicks,
boolean computeDurationViaNanoTicks,
Map tags,
List references) {
this.tracer = tracer;
this.operationName = operationName;
this.context = context;
this.startTimeMicroseconds = startTimeMicroseconds;
this.startTimeNanoTicks = startTimeNanoTicks;
this.computeDurationViaNanoTicks = computeDurationViaNanoTicks;
this.tags = new HashMap();
this.references = references != null ? new ArrayList(references) : null;
for (Map.Entry tag : tags.entrySet()) {
setTagAsObject(tag.getKey(), tag.getValue());
}
}
public long getStart() {
return startTimeMicroseconds;
}
public long getDuration() {
synchronized (this) {
return durationMicroseconds;
}
}
public JaegerTracer getTracer() {
return tracer;
}
public List getReferences() {
if (references == null) {
return Collections.emptyList();
}
return Collections.unmodifiableList(references);
}
public Map getTags() {
synchronized (this) {
return Collections.unmodifiableMap(new HashMap(tags));
}
}
@Override
public JaegerSpan setOperationName(String operationName) {
synchronized (this) {
this.operationName = operationName;
}
return this;
}
public String getOperationName() {
synchronized (this) {
return operationName;
}
}
public String getServiceName() {
synchronized (this) {
return this.getTracer().getServiceName();
}
}
public List getLogs() {
synchronized (this) {
if (logs == null) {
return null;
}
return Collections.unmodifiableList(new ArrayList(logs));
}
}
@Override
public JaegerSpan setBaggageItem(String key, String value) {
if (key == null || (value == null && context.getBaggageItem(key) == null)) {
//Ignore attempts to add new baggage items with null values, they're not accessible anyway
return this;
}
synchronized (this) {
context = tracer.setBaggage(this, key, value);
return this;
}
}
@Override
public String getBaggageItem(String key) {
synchronized (this) {
return this.context.getBaggageItem(key);
}
}
@Override
public String toString() {
synchronized (this) {
return context.toString() + " - " + operationName;
}
}
@Override
public JaegerSpanContext context() {
synchronized (this) {
// doesn't need to be a copy since all fields are final
return context;
}
}
@Override
public void finish() {
if (computeDurationViaNanoTicks) {
long nanoDuration = tracer.clock().currentNanoTicks() - startTimeNanoTicks;
finishWithDuration(nanoDuration / 1000);
} else {
finish(tracer.clock().currentTimeMicros());
}
}
@Override
public void finish(long finishMicros) {
finishWithDuration(finishMicros - startTimeMicroseconds);
}
private void finishWithDuration(long durationMicros) {
synchronized (this) {
if (finished) {
log.warn("Span has already been finished; will not be reported again.");
return;
}
finished = true;
this.durationMicroseconds = durationMicros;
}
if (context.isSampled()) {
tracer.reportSpan(this);
}
}
@Override
public synchronized JaegerSpan setTag(String key, String value) {
return setTagAsObject(key, value);
}
@Override
public synchronized JaegerSpan setTag(String key, boolean value) {
return setTagAsObject(key, value);
}
@Override
public synchronized JaegerSpan setTag(String key, Number value) {
return setTagAsObject(key, value);
}
private JaegerSpan setTagAsObject(String key, Object value) {
if (key.equals(Tags.SAMPLING_PRIORITY.getKey()) && (value instanceof Number)) {
int priority = ((Number) value).intValue();
byte newFlags;
if (priority > 0) {
newFlags = (byte) (context.getFlags() | JaegerSpanContext.flagSampled | JaegerSpanContext.flagDebug);
} else {
newFlags = (byte) (context.getFlags() & (~JaegerSpanContext.flagSampled));
}
context = context.withFlags(newFlags);
}
if (context.isSampled()) {
tags.put(key, value);
}
return this;
}
@Override
public JaegerSpan log(Map fields) {
return log(tracer.clock().currentTimeMicros(), null, fields);
}
@Override
public JaegerSpan log(long timestampMicroseconds, Map fields) {
return log(timestampMicroseconds, null, fields);
}
@Override
public JaegerSpan log(String event) {
return log(tracer.clock().currentTimeMicros(), event, null);
}
@Override
public JaegerSpan log(long timestampMicroseconds, String event) {
return log(timestampMicroseconds, event, null);
}
private JaegerSpan log(long timestampMicroseconds, String event, Map fields) {
synchronized (this) {
if (fields == null && event == null) {
return this;
}
if (context.isSampled()) {
if (fields != null && tracer.isExpandExceptionLogs()) {
fields = addExceptionLogs(fields);
}
if (logs == null) {
this.logs = new ArrayList();
}
logs.add(new LogData(timestampMicroseconds, event, fields));
}
return this;
}
}
/**
* Creates logs related to logged exception
*
* @param fields map containing exception logs which are not present in fields
* @return logged fields
*/
private static Map addExceptionLogs(Map fields) {
Object ex = fields.get(Fields.ERROR_OBJECT);
if (!(ex instanceof Throwable)) {
return fields;
}
Map errorFields = new HashMap(fields);
Throwable loggedException = (Throwable) ex;
if (fields.get(Fields.ERROR_KIND) == null) {
errorFields.put(Fields.ERROR_KIND, loggedException.getClass().getName());
}
if (fields.get(Fields.MESSAGE) == null) {
String message = loggedException.getMessage();
if (message != null) {
errorFields.put(Fields.MESSAGE, message);
}
}
if (fields.get(Fields.STACK) == null) {
StringWriter sw = new StringWriter();
loggedException.printStackTrace(new PrintWriter(sw));
errorFields.put(Fields.STACK, sw.toString());
}
return errorFields;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy