提交 06962636 编写于 作者: wu-sheng's avatar wu-sheng 提交者: GitHub

Merge pull request #199 from wu-sheng/feature/198

 Support leaf span
......@@ -83,7 +83,7 @@ public class Span {
* means no parent span if this {@link TraceSegment}.
* @param operationName {@link #operationName}
*/
private Span(int spanId, int parentSpanId, String operationName) {
protected Span(int spanId, int parentSpanId, String operationName) {
this(spanId, parentSpanId, operationName, System.currentTimeMillis());
}
......@@ -97,7 +97,7 @@ public class Span {
* @param operationName {@link #operationName}
* @param startTime given start timestamp.
*/
private Span(int spanId, int parentSpanId, String operationName, long startTime) {
protected Span(int spanId, int parentSpanId, String operationName, long startTime) {
this();
this.spanId = spanId;
this.parentSpanId = parentSpanId;
......@@ -200,17 +200,17 @@ public class Span {
*
* @return this Span instance, for chaining
*/
public final Span setTag(String key, String value) {
public Span setTag(String key, String value) {
tagsWithStr.put(key, value);
return this;
}
public final Span setTag(String key, boolean value) {
public Span setTag(String key, boolean value) {
tagsWithBool.put(key, value);
return this;
}
public final Span setTag(String key, Integer value) {
public Span setTag(String key, Integer value) {
tagsWithInt.put(key, value);
return this;
}
......@@ -359,6 +359,10 @@ public class Span {
return Collections.unmodifiableList(logs);
}
public boolean isLeaf() {
return false;
}
@Override
public String toString() {
return "Span{" +
......
......@@ -55,11 +55,19 @@ public class ContextManager implements TracerContextListener, BootService {
}
public static Span createSpan(String operationName) {
return get().createSpan(operationName);
return get().createSpan(operationName, false);
}
public static Span createSpan(String operationName, long startTime) {
return get().createSpan(operationName, startTime);
return get().createSpan(operationName, startTime, false);
}
public static Span createLeafSpan(String operationName) {
return get().createSpan(operationName, true);
}
public static Span createLeafSpan(String operationName, long startTime) {
return get().createSpan(operationName, startTime, true);
}
public static Span activeSpan() {
......
package org.skywalking.apm.agent.core.context;
import org.skywalking.apm.trace.Span;
import org.skywalking.apm.trace.TraceSegment;
/**
* LeafSpan is a special type of {@link Span}
*
* In rpc-client tracing scenario, one component could constitute by many other rpc-client.
* e.g Feign constitutes by okhttp, apache httpclient, etc.
*
* By having leaf concept, no need so many spans for single rpc call.
*
* @author wusheng
*/
public class LeafSpan extends Span {
private int stackDepth = 0;
/**
* Create a new span, by given span id and give startTime but no parent span id,
* No parent span id means that, this Span is the first span of the {@link TraceSegment}
*
* @param spanId given by the creator, and must be unique id in the {@link TraceSegment}
* @param operationName {@link #operationName}
* @param startTime given start time of span
*/
public LeafSpan(int spanId, String operationName, long startTime) {
super(spanId, -1, operationName, startTime);
}
/**
* Create a new span, by given span id, parent span, operationName and startTime.
* This span must belong a {@link TraceSegment}, also is a part of Distributed Trace.
*
* @param spanId given by the creator, and must be unique id in the {@link TraceSegment}
* @param parentSpan {@link Span}
* @param operationName {@link #operationName}
* @param startTime given start timestamp
*/
public LeafSpan(int spanId, Span parentSpan, String operationName, long startTime) {
super(spanId, parentSpan.getSpanId(), operationName, startTime);
}
void push() {
stackDepth++;
}
void pop() {
stackDepth--;
}
boolean isFinished() {
return stackDepth == 0;
}
@Override
public boolean isLeaf() {
return true;
}
private boolean isInOwnerContext() {
return stackDepth == 1;
}
/**
* Sets the string name for the logical operation this span represents,
* only when this is in context of the leaf span owner.
*
* @return this Span instance, for chaining
*/
@Override
public Span setOperationName(String operationName) {
if (isInOwnerContext()) {
super.setOperationName(operationName);
}
return this;
}
/**
* Set a key:value tag on the Span,
* only when this is in context of the leaf span owner.
*
* @return this Span instance, for chaining
*/
@Override
public final Span setTag(String key, String value) {
if (isInOwnerContext()) {
super.setTag(key, value);
}
return this;
}
@Override
public final Span setTag(String key, boolean value) {
if (isInOwnerContext()) {
super.setTag(key, value);
}
return this;
}
@Override
public final Span setTag(String key, Integer value) {
if (isInOwnerContext()) {
super.setTag(key, value);
}
return this;
}
}
......@@ -46,26 +46,40 @@ public final class TracerContext {
* @param operationName {@link Span#operationName}
* @return the new active span.
*/
public Span createSpan(String operationName) {
return this.createSpan(operationName, System.currentTimeMillis());
public Span createSpan(String operationName, boolean isLeaf) {
return this.createSpan(operationName, System.currentTimeMillis(), isLeaf);
}
/**
* Create a new span, as an active span, by the given operationName and startTime;
*
* @param operationName {@link Span#operationName}
* @param startTime {@link Span#startTime}
* @param startTime {@link Span#startTime}
* @param isLeaf is true, if the span is a leaf in trace tree.
* @return
*/
public Span createSpan(String operationName, long startTime) {
public Span createSpan(String operationName, long startTime, boolean isLeaf) {
Span parentSpan = peek();
Span span;
if (parentSpan == null) {
span = new Span(spanIdGenerator++, operationName, startTime);
if (isLeaf) {
span = new LeafSpan(spanIdGenerator++, operationName, startTime);
} else {
span = new Span(spanIdGenerator++, operationName, startTime);
}
push(span);
} else if (parentSpan.isLeaf()) {
span = parentSpan;
LeafSpan leafSpan = (LeafSpan)span;
leafSpan.push();
} else {
span = new Span(spanIdGenerator++, parentSpan, operationName, startTime);
if (isLeaf) {
span = new LeafSpan(spanIdGenerator++, parentSpan, operationName, startTime);
} else {
span = new Span(spanIdGenerator++, parentSpan, operationName, startTime);
}
push(span);
}
push(span);
return span;
}
......@@ -98,6 +112,13 @@ public final class TracerContext {
public void stopSpan(Span span, Long endTime) {
Span lastSpan = peek();
if (lastSpan.isLeaf()) {
LeafSpan leafSpan = (LeafSpan)lastSpan;
leafSpan.pop();
if (!leafSpan.isFinished()) {
return;
}
}
if (lastSpan == span) {
pop().finish(segment, endTime);
} else {
......@@ -142,7 +163,7 @@ public final class TracerContext {
* Ref this {@link ContextCarrier} to this {@link TraceSegment}
*
* @param carrier holds the snapshot, if get this {@link ContextCarrier} from remote, make sure {@link
* ContextCarrier#deserialize(String)} called.
* ContextCarrier#deserialize(String)} called.
*/
public void extract(ContextCarrier carrier) {
if (carrier.isValid()) {
......
package org.skywalking.apm.agent.core.context;
import java.util.Map;
import org.junit.Assert;
import org.junit.Test;
/**
* @author wusheng
*/
public class LeafSpanTestCase {
@Test
public void testLeaf() {
LeafSpan span = new LeafSpan(0, "serviceA", System.currentTimeMillis());
span.push();
span.setOperationName("serviceA2");
span.setTag("key", "value-text");
span.setTag("key2", false);
span.setTag("key3", 1);
//start 2nd span
span.push();
Assert.assertFalse(span.isFinished());
Assert.assertTrue(span.isLeaf());
span.setOperationName("service123");
span.setTag("key", "value-text2");
span.setTag("key2", true);
span.setTag("key3", 2);
Assert.assertEquals("serviceA2", span.getOperationName());
Assert.assertEquals("value-text", span.getStrTag("key"));
Assert.assertFalse(span.getBoolTag("key2"));
Assert.assertEquals(1, span.getIntTag("key3").intValue());
//end 2nd span
span.pop();
span.pop();
Assert.assertTrue(span.isFinished());
}
}
......@@ -19,7 +19,7 @@ public class TracerContextTestCase {
@Test
public void testSpanLifeCycle() {
TracerContext context = new TracerContext();
Span span = context.createSpan("/serviceA");
Span span = context.createSpan("/serviceA", false);
Assert.assertEquals(span, context.activeSpan());
......@@ -35,8 +35,8 @@ public class TracerContextTestCase {
@Test
public void testChildOfSpan() {
TracerContext context = new TracerContext();
Span serviceSpan = context.createSpan("/serviceA");
Span dbSpan = context.createSpan("db/preparedStatement/execute");
Span serviceSpan = context.createSpan("/serviceA", false);
Span dbSpan = context.createSpan("db/preparedStatement/execute", false);
Assert.assertEquals(dbSpan, context.activeSpan());
......@@ -60,8 +60,8 @@ public class TracerContextTestCase {
@Test
public void testInject() {
TracerContext context = new TracerContext();
Span serviceSpan = context.createSpan("/serviceA");
Span dbSpan = context.createSpan("db/preparedStatement/execute");
Span serviceSpan = context.createSpan("/serviceA", false);
Span dbSpan = context.createSpan("db/preparedStatement/execute", false);
Tags.PEER_HOST.set(dbSpan, "127.0.0.1");
Tags.PEER_PORT.set(dbSpan, 8080);
......@@ -87,7 +87,7 @@ public class TracerContextTestCase {
TracerContext context = new TracerContext();
context.extract(carrier);
Span span = context.createSpan("/serviceC");
Span span = context.createSpan("/serviceC", false);
TracerContext.ListenerManager.add(TestTracerContextListener.INSTANCE);
final TraceSegment[] finishedSegmentCarrier = TestTracerContextListener.INSTANCE.finishedSegmentCarrier;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册